summaryrefslogtreecommitdiff
path: root/chromium/components/signin
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-13 16:23:34 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-14 10:37:21 +0000
commit38a9a29f4f9436cace7f0e7abf9c586057df8a4e (patch)
treec4e8c458dc595bc0ddb435708fa2229edfd00bd4 /chromium/components/signin
parente684a3455bcc29a6e3e66a004e352dea4e1141e7 (diff)
downloadqtwebengine-chromium-38a9a29f4f9436cace7f0e7abf9c586057df8a4e.tar.gz
BASELINE: Update Chromium to 73.0.3683.37
Change-Id: I08c9af2948b645f671e5d933aca1f7a90ea372f2 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/components/signin')
-rw-r--r--chromium/components/signin/core/browser/BUILD.gn91
-rw-r--r--chromium/components/signin/core/browser/about_signin_internals.cc25
-rw-r--r--chromium/components/signin/core/browser/about_signin_internals.h25
-rw-r--r--chromium/components/signin/core/browser/account_consistency_method.h3
-rw-r--r--chromium/components/signin/core/browser/account_fetcher_service.cc39
-rw-r--r--chromium/components/signin/core/browser/account_fetcher_service.h27
-rw-r--r--chromium/components/signin/core/browser/account_info.cc52
-rw-r--r--chromium/components/signin/core/browser/account_info.h8
-rw-r--r--chromium/components/signin/core/browser/account_info_unittest.cc43
-rw-r--r--chromium/components/signin/core/browser/account_info_util.cc73
-rw-r--r--chromium/components/signin/core/browser/account_info_util.h17
-rw-r--r--chromium/components/signin/core/browser/account_info_util_unittest.cc158
-rw-r--r--chromium/components/signin/core/browser/account_investigator.cc35
-rw-r--r--chromium/components/signin/core/browser/account_investigator.h23
-rw-r--r--chromium/components/signin/core/browser/account_investigator_unittest.cc116
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor.cc148
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor.h46
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor_unittest.cc681
-rw-r--r--chromium/components/signin/core/browser/account_tracker_service.cc358
-rw-r--r--chromium/components/signin/core/browser/account_tracker_service.h57
-rw-r--r--chromium/components/signin/core/browser/account_tracker_service_unittest.cc63
-rw-r--r--chromium/components/signin/core/browser/android/BUILD.gn5
-rw-r--r--chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java175
-rw-r--r--chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountTrackerService.java253
-rw-r--r--chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/OAuth2TokenService.java500
-rw-r--r--chromium/components/signin/core/browser/child_account_info_fetcher.cc39
-rw-r--r--chromium/components/signin/core/browser/child_account_info_fetcher.h42
-rw-r--r--chromium/components/signin/core/browser/child_account_info_fetcher_android.cc13
-rw-r--r--chromium/components/signin/core/browser/child_account_info_fetcher_android.h8
-rw-r--r--chromium/components/signin/core/browser/child_account_info_fetcher_impl.cc181
-rw-r--r--chromium/components/signin/core/browser/child_account_info_fetcher_impl.h84
-rw-r--r--chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc14
-rw-r--r--chromium/components/signin/core/browser/dice_account_reconcilor_delegate_unittest.cc9
-rw-r--r--chromium/components/signin/core/browser/dice_header_helper.cc18
-rw-r--r--chromium/components/signin/core/browser/fake_account_fetcher_service.cc14
-rw-r--r--chromium/components/signin/core/browser/fake_account_fetcher_service.h3
-rw-r--r--chromium/components/signin/core/browser/fake_auth_status_provider.cc30
-rw-r--r--chromium/components/signin/core/browser/fake_auth_status_provider.h38
-rw-r--r--chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc113
-rw-r--r--chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h47
-rw-r--r--chromium/components/signin/core/browser/fake_signin_manager.cc24
-rw-r--r--chromium/components/signin/core/browser/fake_signin_manager.h14
-rw-r--r--chromium/components/signin/core/browser/gaia_cookie_manager_service.cc89
-rw-r--r--chromium/components/signin/core/browser/gaia_cookie_manager_service.h44
-rw-r--r--chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc148
-rw-r--r--chromium/components/signin/core/browser/list_accounts_test_utils.cc93
-rw-r--r--chromium/components/signin/core/browser/list_accounts_test_utils.h67
-rw-r--r--chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h13
-rw-r--r--chromium/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate.cc944
-rw-r--r--chromium/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate.h236
-rw-r--r--chromium/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate_unittest.cc1615
-rw-r--r--chromium/components/signin/core/browser/oauth2_token_service_delegate_android.cc529
-rw-r--r--chromium/components/signin/core/browser/oauth2_token_service_delegate_android.h132
-rw-r--r--chromium/components/signin/core/browser/profile_oauth2_token_service.cc15
-rw-r--r--chromium/components/signin/core/browser/profile_oauth2_token_service.h13
-rw-r--r--chromium/components/signin/core/browser/signin_error_controller.cc122
-rw-r--r--chromium/components/signin/core/browser/signin_error_controller.h61
-rw-r--r--chromium/components/signin/core/browser/signin_error_controller_unittest.cc430
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper_unittest.cc35
-rw-r--r--chromium/components/signin/core/browser/signin_internals_util.cc2
-rw-r--r--chromium/components/signin/core/browser/signin_internals_util.h10
-rw-r--r--chromium/components/signin/core/browser/signin_investigator_unittest.cc15
-rw-r--r--chromium/components/signin/core/browser/signin_manager.cc69
-rw-r--r--chromium/components/signin/core/browser/signin_manager.h16
-rw-r--r--chromium/components/signin/core/browser/signin_manager_base.cc36
-rw-r--r--chromium/components/signin/core/browser/signin_manager_base.h35
-rw-r--r--chromium/components/signin/core/browser/signin_manager_unittest.cc21
-rw-r--r--chromium/components/signin/core/browser/signin_metrics.cc14
-rw-r--r--chromium/components/signin/core/browser/signin_metrics.h6
-rw-r--r--chromium/components/signin/core/browser/signin_metrics_unittest.cc2
-rw-r--r--chromium/components/signin/core/browser/signin_pref_names.cc13
-rw-r--r--chromium/components/signin/core/browser/signin_pref_names.h2
-rw-r--r--chromium/components/signin/core/browser/signin_tracker.cc31
-rw-r--r--chromium/components/signin/core/browser/signin_tracker.h57
-rw-r--r--chromium/components/signin/core/browser/signin_tracker_unittest.cc58
-rw-r--r--chromium/components/signin/core/browser/ubertoken_fetcher.cc15
-rw-r--r--chromium/components/signin/core/browser/ubertoken_fetcher.h35
-rw-r--r--chromium/components/signin/core/browser/ubertoken_fetcher_impl.cc156
-rw-r--r--chromium/components/signin/core/browser/ubertoken_fetcher_impl.h108
-rw-r--r--chromium/components/signin/core/browser/ubertoken_fetcher_impl_unittest.cc179
-rw-r--r--chromium/components/signin/ios/DEPS1
-rw-r--r--chromium/components/signin/ios/browser/BUILD.gn6
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service.h18
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service.mm18
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service_unittest.mm49
-rw-r--r--chromium/components/signin/ios/browser/oauth2_token_service_observer_bridge.h57
-rw-r--r--chromium/components/signin/ios/browser/oauth2_token_service_observer_bridge.mm52
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h30
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm61
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm26
90 files changed, 6988 insertions, 2508 deletions
diff --git a/chromium/components/signin/core/browser/BUILD.gn b/chromium/components/signin/core/browser/BUILD.gn
index ad4cd91b5c2..d85aaee4e6e 100644
--- a/chromium/components/signin/core/browser/BUILD.gn
+++ b/chromium/components/signin/core/browser/BUILD.gn
@@ -24,6 +24,10 @@ static_library("shared") {
sources = [
"account_info.cc",
"account_info.h",
+ "account_info_util.cc",
+ "account_info_util.h",
+ "avatar_icon_util.cc",
+ "avatar_icon_util.h",
"identity_utils.cc",
"identity_utils.h",
"signin_metrics.cc",
@@ -32,12 +36,17 @@ static_library("shared") {
"signin_pref_names.h",
"signin_switches.cc",
"signin_switches.h",
+ "ubertoken_fetcher.cc",
+ "ubertoken_fetcher.h",
]
deps = [
":signin_buildflags",
"//components/account_id",
"//components/prefs:prefs",
"//third_party/icu:icui18n",
+ "//third_party/re2",
+ "//ui/gfx",
+ "//url",
]
public_deps = [
"//base",
@@ -57,8 +66,14 @@ static_library("internals") {
sources = [
"account_consistency_method.cc",
"account_consistency_method.h",
+ "account_fetcher_service.cc",
+ "account_fetcher_service.h",
+ "account_info_fetcher.cc",
+ "account_info_fetcher.h",
"account_tracker_service.cc",
"account_tracker_service.h",
+ "child_account_info_fetcher_android.cc",
+ "child_account_info_fetcher_android.h",
"device_id_helper.cc",
"device_id_helper.h",
"gaia_cookie_manager_service.cc",
@@ -67,14 +82,14 @@ static_library("internals") {
"profile_oauth2_token_service.h",
"signin_client.cc",
"signin_client.h",
- "signin_error_controller.cc",
- "signin_error_controller.h",
"signin_internals_util.cc",
"signin_internals_util.h",
"signin_manager.cc",
"signin_manager.h",
"signin_manager_base.cc",
"signin_manager_base.h",
+ "ubertoken_fetcher_impl.cc",
+ "ubertoken_fetcher_impl.h",
]
if (is_chromeos) {
@@ -83,8 +98,10 @@ static_library("internals") {
deps = [
":shared",
+ ":signin_buildflags",
"//base",
"//components/data_use_measurement/core",
+ "//components/image_fetcher/core",
"//components/keyed_service/core",
"//components/prefs",
"//google_apis",
@@ -93,30 +110,22 @@ static_library("internals") {
"//services/network/public/mojom",
"//ui/gfx",
]
+
+ if (is_android) {
+ deps += [ "android:jni_headers" ]
+ }
}
static_library("browser") {
sources = [
"about_signin_internals.cc",
"about_signin_internals.h",
- "account_fetcher_service.cc",
- "account_fetcher_service.h",
- "account_info_fetcher.cc",
- "account_info_fetcher.h",
"account_investigator.cc",
"account_investigator.h",
"account_reconcilor.cc",
"account_reconcilor.h",
"account_reconcilor_delegate.cc",
"account_reconcilor_delegate.h",
- "avatar_icon_util.cc",
- "avatar_icon_util.h",
- "child_account_info_fetcher.cc",
- "child_account_info_fetcher.h",
- "child_account_info_fetcher_android.cc",
- "child_account_info_fetcher_android.h",
- "child_account_info_fetcher_impl.cc",
- "child_account_info_fetcher_impl.h",
"chrome_connected_header_helper.cc",
"chrome_connected_header_helper.h",
"cookie_settings_util.cc",
@@ -127,6 +136,12 @@ static_library("browser") {
"dice_header_helper.h",
"mirror_account_reconcilor_delegate.cc",
"mirror_account_reconcilor_delegate.h",
+ "mutable_profile_oauth2_token_service_delegate.cc",
+ "mutable_profile_oauth2_token_service_delegate.h",
+ "oauth2_token_service_delegate_android.cc",
+ "oauth2_token_service_delegate_android.h",
+ "signin_error_controller.cc",
+ "signin_error_controller.h",
"signin_header_helper.cc",
"signin_header_helper.h",
"signin_investigator.cc",
@@ -168,7 +183,6 @@ static_library("browser") {
"//base:i18n",
"//components/data_use_measurement/core",
"//components/google/core/browser",
- "//components/image_fetcher/core",
"//components/metrics",
"//components/os_crypt",
"//components/webdata/common",
@@ -178,7 +192,6 @@ static_library("browser") {
"//skia",
"//sql",
"//third_party/icu",
- "//third_party/re2",
]
if (is_chromeos) {
@@ -198,10 +211,6 @@ static_library("browser") {
}
if (is_android) {
- sources -= [
- "child_account_info_fetcher_impl.cc",
- "child_account_info_fetcher_impl.h",
- ]
deps += [ "android:jni_headers" ]
}
}
@@ -214,20 +223,29 @@ static_library("browser") {
static_library("internals_test_support") {
testonly = true
sources = [
+ "fake_account_fetcher_service.cc",
+ "fake_account_fetcher_service.h",
"fake_gaia_cookie_manager_service.cc",
"fake_gaia_cookie_manager_service.h",
"fake_profile_oauth2_token_service.cc",
"fake_profile_oauth2_token_service.h",
"fake_signin_manager.cc",
"fake_signin_manager.h",
+
+ # TODO(https://crbug.com/907782): Move list_accounts_test_utils to
+ # //services/identity/public/cpp once FakeGCMS no longer depends on it.
+ "list_accounts_test_utils.cc",
+ "list_accounts_test_utils.h",
"test_signin_client.cc",
"test_signin_client.h",
]
deps = [
"//base/test:test_support",
+ "//components/image_fetcher/core",
"//components/prefs",
"//google_apis:test_support",
+ "//ui/gfx:test_support",
]
public_deps = [
@@ -238,36 +256,11 @@ static_library("internals_test_support") {
]
}
-static_library("test_support") {
- testonly = true
- sources = [
- "fake_account_fetcher_service.cc",
- "fake_account_fetcher_service.h",
- "fake_auth_status_provider.cc",
- "fake_auth_status_provider.h",
- ]
-
- deps = [
- "//ui/gfx:test_support",
- ]
-
- public_deps = [
- ":browser",
-
- # This public_dep is present to avoid requiring all consumers of this
- # target to also depend on the below target. Once there are no direct
- # consumers of the internals_test_support target, this dep should be
- # removed. See https://crbug.com/796544.
- ":internals_test_support",
- "//base",
- "//components/image_fetcher/core/",
- ]
-}
-
source_set("unit_tests") {
testonly = true
sources = [
"account_info_unittest.cc",
+ "account_info_util_unittest.cc",
"account_investigator_unittest.cc",
"account_reconcilor_delegate_unittest.cc",
"account_reconcilor_unittest.cc",
@@ -277,6 +270,7 @@ source_set("unit_tests") {
"dice_account_reconcilor_delegate_unittest.cc",
"gaia_cookie_manager_service_unittest.cc",
"identity_utils_unittest.cc",
+ "mutable_profile_oauth2_token_service_delegate_unittest.cc",
"signin_error_controller_unittest.cc",
"signin_header_helper_unittest.cc",
"signin_investigator_unittest.cc",
@@ -284,14 +278,17 @@ source_set("unit_tests") {
"signin_metrics_unittest.cc",
"signin_status_metrics_provider_unittest.cc",
"signin_tracker_unittest.cc",
+ "ubertoken_fetcher_impl_unittest.cc",
"webdata/token_service_table_unittest.cc",
]
deps = [
+ ":browser",
+ ":internals_test_support",
":signin_buildflags",
- ":test_support",
"//base/test:test_support",
"//components/content_settings/core/browser",
+ "//components/image_fetcher/core",
"//components/os_crypt:test_support",
"//components/prefs",
"//components/prefs:test_support",
diff --git a/chromium/components/signin/core/browser/about_signin_internals.cc b/chromium/components/signin/core/browser/about_signin_internals.cc
index 2139af774d6..ad8dd0679f8 100644
--- a/chromium/components/signin/core/browser/about_signin_internals.cc
+++ b/chromium/components/signin/core/browser/about_signin_internals.cc
@@ -25,7 +25,6 @@
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_client.h"
#include "components/signin/core/browser/signin_internals_util.h"
-#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/core/browser/signin_switches.h"
#include "google_apis/gaia/oauth2_token_service_delegate.h"
#include "net/base/backoff_entry.h"
@@ -125,10 +124,6 @@ std::string SigninStatusFieldToLabel(
return "Gaia Authentication Result";
case signin_internals_util::REFRESH_TOKEN_RECEIVED:
return "RefreshToken Received";
- case signin_internals_util::SIGNIN_STARTED:
- return "SigninManager Started";
- case signin_internals_util::SIGNIN_COMPLETED:
- return "SigninManager Completed";
case signin_internals_util::TIMED_FIELDS_END:
NOTREACHED();
return "Error";
@@ -173,8 +168,6 @@ std::string GetAccountConsistencyDescription(
return "None";
case signin::AccountConsistencyMethod::kMirror:
return "Mirror";
- case signin::AccountConsistencyMethod::kDiceFixAuthErrors:
- return "DICE fixing auth errors";
case signin::AccountConsistencyMethod::kDiceMigration:
return "DICE migration";
case signin::AccountConsistencyMethod::kDice:
@@ -190,14 +183,12 @@ AboutSigninInternals::AboutSigninInternals(
ProfileOAuth2TokenService* token_service,
AccountTrackerService* account_tracker,
identity::IdentityManager* identity_manager,
- SigninManagerBase* signin_manager,
SigninErrorController* signin_error_controller,
GaiaCookieManagerService* cookie_manager_service,
signin::AccountConsistencyMethod account_consistency)
: token_service_(token_service),
account_tracker_(account_tracker),
identity_manager_(identity_manager),
- signin_manager_(signin_manager),
client_(nullptr),
signin_error_controller_(signin_error_controller),
cookie_manager_service_(cookie_manager_service),
@@ -252,7 +243,7 @@ void AboutSigninInternals::RemoveSigninObserver(
signin_observers_.RemoveObserver(observer);
}
-void AboutSigninInternals::NotifySigninValueChanged(
+void AboutSigninInternals::NotifyTimedSigninFieldValueChanged(
const signin_internals_util::TimedSigninStatusField& field,
const std::string& value) {
unsigned int field_index = field - signin_internals_util::TIMED_FIELDS_BEGIN;
@@ -274,8 +265,6 @@ void AboutSigninInternals::NotifySigninValueChanged(
if (field == signin_internals_util::AUTHENTICATION_RESULT_RECEIVED) {
ClearPref(client_->GetPrefs(),
signin_internals_util::REFRESH_TOKEN_RECEIVED);
- ClearPref(client_->GetPrefs(), signin_internals_util::SIGNIN_STARTED);
- ClearPref(client_->GetPrefs(), signin_internals_util::SIGNIN_COMPLETED);
}
NotifyObservers();
@@ -313,8 +302,6 @@ void AboutSigninInternals::Initialize(SigninClient* client) {
signin_error_controller_->AddObserver(this);
identity_manager_->AddObserver(this);
identity_manager_->AddDiagnosticsObserver(this);
- signin_manager_->AddSigninDiagnosticsObserver(this);
- token_service_->AddObserver(this);
token_service_->AddDiagnosticsObserver(this);
cookie_manager_service_->AddObserver(this);
}
@@ -323,8 +310,6 @@ void AboutSigninInternals::Shutdown() {
signin_error_controller_->RemoveObserver(this);
identity_manager_->RemoveObserver(this);
identity_manager_->RemoveDiagnosticsObserver(this);
- signin_manager_->RemoveSigninDiagnosticsObserver(this);
- token_service_->RemoveObserver(this);
token_service_->RemoveDiagnosticsObserver(this);
cookie_manager_service_->RemoveObserver(this);
}
@@ -415,7 +400,7 @@ void AboutSigninInternals::OnRefreshTokensLoaded() {
NotifyObservers();
}
-void AboutSigninInternals::OnEndBatchChanges() {
+void AboutSigninInternals::OnEndBatchOfRefreshTokenStateChanges() {
NotifyObservers();
}
@@ -431,13 +416,13 @@ void AboutSigninInternals::OnAccessTokenRemoved(
}
void AboutSigninInternals::OnRefreshTokenReceived(const std::string& status) {
- NotifySigninValueChanged(signin_internals_util::REFRESH_TOKEN_RECEIVED,
- status);
+ NotifyTimedSigninFieldValueChanged(
+ signin_internals_util::REFRESH_TOKEN_RECEIVED, status);
}
void AboutSigninInternals::OnAuthenticationResultReceived(
const std::string& status) {
- NotifySigninValueChanged(
+ NotifyTimedSigninFieldValueChanged(
signin_internals_util::AUTHENTICATION_RESULT_RECEIVED, status);
}
diff --git a/chromium/components/signin/core/browser/about_signin_internals.h b/chromium/components/signin/core/browser/about_signin_internals.h
index 23aa4fd8973..5ce029fbc09 100644
--- a/chromium/components/signin/core/browser/about_signin_internals.h
+++ b/chromium/components/signin/core/browser/about_signin_internals.h
@@ -17,8 +17,6 @@
#include "components/signin/core/browser/gaia_cookie_manager_service.h"
#include "components/signin/core/browser/signin_client.h"
#include "components/signin/core/browser/signin_error_controller.h"
-#include "components/signin/core/browser/signin_internals_util.h"
-#include "components/signin/core/browser/signin_manager.h"
#include "google_apis/gaia/oauth2_token_service.h"
#include "services/identity/public/cpp/identity_manager.h"
@@ -39,8 +37,6 @@ using TimedSigninStatusValue = std::pair<std::string, std::string>;
// to propagate to about:signin-internals via SigninInternalsUI.
class AboutSigninInternals
: public KeyedService,
- public signin_internals_util::SigninDiagnosticsObserver,
- public OAuth2TokenService::Observer,
public OAuth2TokenService::DiagnosticsObserver,
public GaiaCookieManagerService::Observer,
SigninErrorController::Observer,
@@ -60,7 +56,6 @@ class AboutSigninInternals
AboutSigninInternals(ProfileOAuth2TokenService* token_service,
AccountTrackerService* account_tracker,
identity::IdentityManager* identity_manager,
- SigninManagerBase* signin_manager,
SigninErrorController* signin_error_controller,
GaiaCookieManagerService* cookie_manager_service,
signin::AccountConsistencyMethod account_consistency);
@@ -196,12 +191,7 @@ class AboutSigninInternals
signin::AccountConsistencyMethod account_consistency);
};
- // SigninManager::SigninDiagnosticsObserver implementation.
- void NotifySigninValueChanged(
- const signin_internals_util::TimedSigninStatusField& field,
- const std::string& value) override;
-
- // IdentityMager::DiagnosticsObserver implementations.
+ // IdentityManager::DiagnosticsObserver implementations.
void OnAccessTokenRequested(const std::string& account_id,
const std::string& consumer_id,
const identity::ScopeSet& scopes) override;
@@ -221,17 +211,19 @@ class AboutSigninInternals
void OnRefreshTokenRevokedFromSource(const std::string& account_id,
const std::string& source) override;
- // OAuth2TokenServiceDelegate::Observer implementations.
- void OnRefreshTokensLoaded() override;
- void OnEndBatchChanges() override;
-
// IdentityManager::Observer implementations.
+ void OnRefreshTokensLoaded() override;
+ void OnEndBatchOfRefreshTokenStateChanges() override;
void OnPrimaryAccountSigninFailed(
const GoogleServiceAuthError& error) override;
void OnPrimaryAccountSet(const AccountInfo& primary_account_info) override;
void OnPrimaryAccountCleared(
const AccountInfo& primary_account_info) override;
+ void NotifyTimedSigninFieldValueChanged(
+ const signin_internals_util::TimedSigninStatusField& field,
+ const std::string& value);
+
void NotifyObservers();
// SigninErrorController::Observer implementation
@@ -246,9 +238,6 @@ class AboutSigninInternals
// Weak pointer to the identity manager.
identity::IdentityManager* identity_manager_;
- // Weak pointer to the signin manager.
- SigninManagerBase* signin_manager_;
-
// Weak pointer to the client.
SigninClient* client_;
diff --git a/chromium/components/signin/core/browser/account_consistency_method.h b/chromium/components/signin/core/browser/account_consistency_method.h
index f1d1b38026c..bee4dc36835 100644
--- a/chromium/components/signin/core/browser/account_consistency_method.h
+++ b/chromium/components/signin/core/browser/account_consistency_method.h
@@ -21,9 +21,6 @@ enum class AccountConsistencyMethod : int {
// Account management UI in the avatar bubble.
kMirror,
- // No account consistency, but Dice fixes authentication errors.
- kDiceFixAuthErrors,
-
// Account management UI on Gaia webpages is enabled once the accounts become
// consistent.
kDiceMigration,
diff --git a/chromium/components/signin/core/browser/account_fetcher_service.cc b/chromium/components/signin/core/browser/account_fetcher_service.cc
index 5377efb4acc..23a8aa36d01 100644
--- a/chromium/components/signin/core/browser/account_fetcher_service.cc
+++ b/chromium/components/signin/core/browser/account_fetcher_service.cc
@@ -17,11 +17,14 @@
#include "components/signin/core/browser/account_info_fetcher.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/avatar_icon_util.h"
-#include "components/signin/core/browser/child_account_info_fetcher.h"
#include "components/signin/core/browser/signin_client.h"
#include "components/signin/core/browser/signin_switches.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
+#if defined(OS_ANDROID)
+#include "components/signin/core/browser/child_account_info_fetcher_android.h"
+#endif
+
namespace {
const base::TimeDelta kRefreshFromTokenServiceDelay =
@@ -53,8 +56,11 @@ AccountFetcherService::AccountFetcherService()
profile_loaded_(false),
refresh_tokens_loaded_(false),
shutdown_called_(false),
- scheduled_refresh_enabled_(true),
- child_info_request_(nullptr) {}
+#if defined(OS_ANDROID)
+ child_info_request_(nullptr),
+#endif
+ scheduled_refresh_enabled_(true) {
+}
AccountFetcherService::~AccountFetcherService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -91,9 +97,11 @@ void AccountFetcherService::Initialize(
void AccountFetcherService::Shutdown() {
token_service_->RemoveObserver(this);
+#if defined(OS_ANDROID)
// child_info_request_ is an invalidation handler and needs to be
// unregistered during the lifetime of the invalidation service.
child_info_request_.reset();
+#endif
invalidation_service_ = nullptr;
shutdown_called_ = true;
}
@@ -113,7 +121,9 @@ void AccountFetcherService::SetupInvalidationsOnProfileLoad(
DCHECK(!invalidation_service_);
DCHECK(!profile_loaded_);
DCHECK(!network_fetches_enabled_);
+#if defined(OS_ANDROID)
DCHECK(!child_info_request_);
+#endif
invalidation_service_ = invalidation_service;
profile_loaded_ = true;
MaybeEnableNetworkFetches();
@@ -215,12 +225,12 @@ void AccountFetcherService::StartFetchingUserInfo(
}
}
+#if defined(OS_ANDROID)
// Starts fetching whether this is a child account. Handles refresh internally.
void AccountFetcherService::StartFetchingChildInfo(
const std::string& account_id) {
- child_info_request_ = ChildAccountInfoFetcher::CreateFrom(
- child_request_account_id_, this, token_service_,
- signin_client_->GetURLLoaderFactory(), invalidation_service_);
+ child_info_request_ =
+ ChildAccountInfoFetcherAndroid::Create(this, child_request_account_id_);
}
void AccountFetcherService::ResetChildInfo() {
@@ -230,6 +240,13 @@ void AccountFetcherService::ResetChildInfo() {
child_info_request_.reset();
}
+void AccountFetcherService::SetIsChildAccount(const std::string& account_id,
+ bool is_child_account) {
+ if (child_request_account_id_ == account_id)
+ account_tracker_service_->SetIsChildAccount(account_id, is_child_account);
+}
+#endif
+
void AccountFetcherService::RefreshAccountInfo(const std::string& account_id,
bool only_fetch_if_invalid) {
DCHECK(network_fetches_enabled_);
@@ -253,8 +270,8 @@ void AccountFetcherService::RefreshAccountInfo(const std::string& account_id,
void AccountFetcherService::OnUserInfoFetchSuccess(
const std::string& account_id,
std::unique_ptr<base::DictionaryValue> user_info) {
- account_tracker_service_->SetAccountStateFromUserInfo(account_id,
- user_info.get());
+ account_tracker_service_->SetAccountInfoFromUserInfo(account_id,
+ user_info.get());
FetchAccountImage(account_id);
user_info_requests_.erase(account_id);
}
@@ -309,12 +326,6 @@ void AccountFetcherService::FetchAccountImage(const std::string& account_id) {
callback, traffic_annotation);
}
-void AccountFetcherService::SetIsChildAccount(const std::string& account_id,
- bool is_child_account) {
- if (child_request_account_id_ == account_id)
- account_tracker_service_->SetIsChildAccount(account_id, is_child_account);
-}
-
void AccountFetcherService::OnUserInfoFetchFailure(
const std::string& account_id) {
LOG(WARNING) << "Failed to get UserInfo for " << account_id;
diff --git a/chromium/components/signin/core/browser/account_fetcher_service.h b/chromium/components/signin/core/browser/account_fetcher_service.h
index 77eb45911f7..7ced83d8402 100644
--- a/chromium/components/signin/core/browser/account_fetcher_service.h
+++ b/chromium/components/signin/core/browser/account_fetcher_service.h
@@ -13,17 +13,21 @@
#include "base/macros.h"
#include "base/sequence_checker.h"
#include "base/timer/timer.h"
+#include "build/build_config.h"
#include "components/keyed_service/core/keyed_service.h"
#include "google_apis/gaia/oauth2_token_service.h"
#include "ui/gfx/image/image.h"
class AccountInfoFetcher;
class AccountTrackerService;
-class ChildAccountInfoFetcher;
class OAuth2TokenService;
class PrefRegistrySimple;
class SigninClient;
+#if defined(OS_ANDROID)
+class ChildAccountInfoFetcherAndroid;
+#endif
+
namespace base {
class DictionaryValue;
}
@@ -38,9 +42,6 @@ namespace invalidation {
class InvalidationService;
}
-// TODO(maroun): Protect with macro for Android only everything that is related
-// to child account info fetching.
-
class AccountFetcherService : public KeyedService,
public OAuth2TokenService::Observer {
public:
@@ -83,8 +84,10 @@ class AccountFetcherService : public KeyedService,
void EnableNetworkFetchesForTest();
- // Called by ChildAccountInfoFetcher.
+#if defined(OS_ANDROID)
+ // Called by ChildAccountInfoFetcherAndroid.
void SetIsChildAccount(const std::string& account_id, bool is_child_account);
+#endif
// OAuth2TokenService::Observer implementation.
void OnRefreshTokenAvailable(const std::string& account_id) override;
@@ -93,15 +96,16 @@ class AccountFetcherService : public KeyedService,
private:
friend class AccountInfoFetcher;
- friend class ChildAccountInfoFetcherImpl;
void RefreshAllAccountInfo(bool only_fetch_if_invalid);
void RefreshAllAccountsAndScheduleNext();
void ScheduleNextRefresh();
+#if defined(OS_ANDROID)
// Called on all account state changes. Decides whether to fetch new child
// status information or reset old values that aren't valid now.
void UpdateChildInfo();
+#endif
void MaybeEnableNetworkFetches();
@@ -109,11 +113,13 @@ class AccountFetcherService : public KeyedService,
// Further the two fetches are managed by a different refresh logic and
// thus, can not be combined.
virtual void StartFetchingUserInfo(const std::string& account_id);
+#if defined(OS_ANDROID)
virtual void StartFetchingChildInfo(const std::string& account_id);
// If there is more than one account in a profile, we forcibly reset the
// child status for an account to be false.
void ResetChildInfo();
+#endif
// Refreshes the AccountInfo associated with |account_id|.
void RefreshAccountInfo(const std::string& account_id,
@@ -143,11 +149,14 @@ class AccountFetcherService : public KeyedService,
base::Time last_updated_;
base::OneShotTimer timer_;
bool shutdown_called_;
- // Only disabled in tests.
- bool scheduled_refresh_enabled_;
+#if defined(OS_ANDROID)
std::string child_request_account_id_;
- std::unique_ptr<ChildAccountInfoFetcher> child_info_request_;
+ std::unique_ptr<ChildAccountInfoFetcherAndroid> child_info_request_;
+#endif
+
+ // Only disabled in tests.
+ bool scheduled_refresh_enabled_;
// Holds references to account info fetchers keyed by account_id.
std::unordered_map<std::string, std::unique_ptr<AccountInfoFetcher>>
diff --git a/chromium/components/signin/core/browser/account_info.cc b/chromium/components/signin/core/browser/account_info.cc
index b795bccd57d..8fc78378066 100644
--- a/chromium/components/signin/core/browser/account_info.cc
+++ b/chromium/components/signin/core/browser/account_info.cc
@@ -6,22 +6,40 @@
namespace {
-bool UpdateField(std::string* field, const std::string& new_value) {
- bool should_update = field->empty() && !new_value.empty();
- if (should_update)
- *field = new_value;
- return should_update;
+// Updates |field| with |new_value| if non-empty and different; if |new_value|
+// is equal to |default_value| then it won't override |field| unless it is not
+// set. Returns whether |field| was changed.
+bool UpdateField(std::string* field,
+ const std::string& new_value,
+ const char* default_value) {
+ if (*field == new_value || new_value.empty())
+ return false;
+
+ if (!field->empty() && default_value && new_value == default_value)
+ return false;
+
+ *field = new_value;
+ return true;
}
+// Updates |field| with |new_value| if true. Returns whether |field| was
+// changed.
bool UpdateField(bool* field, bool new_value) {
- bool should_update = !*field && new_value;
- if (should_update)
- *field = new_value;
- return should_update;
+ if (*field == new_value || !new_value)
+ return false;
+
+ *field = new_value;
+ return true;
}
} // namespace
+// This must be a string which can never be a valid domain.
+const char kNoHostedDomainFound[] = "NO_HOSTED_DOMAIN";
+
+// This must be a string which can never be a valid picture URL.
+const char kNoPictureURLFound[] = "NO_PICTURE_URL";
+
AccountInfo::AccountInfo() = default;
AccountInfo::~AccountInfo() = default;
@@ -52,13 +70,15 @@ bool AccountInfo::UpdateWith(const AccountInfo& other) {
return false;
}
- bool modified = UpdateField(&gaia, other.gaia);
- modified |= UpdateField(&email, other.email);
- modified |= UpdateField(&full_name, other.full_name);
- modified |= UpdateField(&given_name, other.given_name);
- modified |= UpdateField(&hosted_domain, other.hosted_domain);
- modified |= UpdateField(&locale, other.locale);
- modified |= UpdateField(&picture_url, other.picture_url);
+ bool modified = false;
+ modified |= UpdateField(&gaia, other.gaia, nullptr);
+ modified |= UpdateField(&email, other.email, nullptr);
+ modified |= UpdateField(&full_name, other.full_name, nullptr);
+ modified |= UpdateField(&given_name, other.given_name, nullptr);
+ modified |=
+ UpdateField(&hosted_domain, other.hosted_domain, kNoHostedDomainFound);
+ modified |= UpdateField(&locale, other.locale, nullptr);
+ modified |= UpdateField(&picture_url, other.picture_url, kNoPictureURLFound);
modified |= UpdateField(&is_child_account, other.is_child_account);
modified |= UpdateField(&is_under_advanced_protection,
other.is_under_advanced_protection);
diff --git a/chromium/components/signin/core/browser/account_info.h b/chromium/components/signin/core/browser/account_info.h
index 4856bee87a0..9be08af8f5f 100644
--- a/chromium/components/signin/core/browser/account_info.h
+++ b/chromium/components/signin/core/browser/account_info.h
@@ -8,6 +8,13 @@
#include <string>
#include "components/account_id/account_id.h"
+#include "ui/gfx/image/image.h"
+
+// Value representing no hosted domain associated with an account.
+extern const char kNoHostedDomainFound[];
+
+// Value representing no picture URL associated with an account.
+extern const char kNoPictureURLFound[];
// Information about a specific account.
struct AccountInfo {
@@ -30,6 +37,7 @@ struct AccountInfo {
std::string hosted_domain;
std::string locale;
std::string picture_url;
+ gfx::Image account_image;
bool is_child_account = false;
bool is_under_advanced_protection = false;
diff --git a/chromium/components/signin/core/browser/account_info_unittest.cc b/chromium/components/signin/core/browser/account_info_unittest.cc
index 844632d7134..2329095b45a 100644
--- a/chromium/components/signin/core/browser/account_info_unittest.cc
+++ b/chromium/components/signin/core/browser/account_info_unittest.cc
@@ -47,8 +47,8 @@ TEST_F(AccountInfoTest, IsValid) {
EXPECT_TRUE(info.IsValid());
}
-// Tests that UpdateWith() correctly ignores parameters with a different account
-// id.
+// Tests that UpdateWith() correctly ignores parameters with a different
+// account / id.
TEST_F(AccountInfoTest, UpdateWithDifferentAccountId) {
AccountInfo info;
info.account_id = "test_id";
@@ -61,7 +61,8 @@ TEST_F(AccountInfoTest, UpdateWithDifferentAccountId) {
EXPECT_TRUE(info.email.empty());
}
-// Tests that UpdateWith() doesn't update the fields that were already set.
+// Tests that UpdateWith() doesn't update the fields that were already set
+// to the correct value.
TEST_F(AccountInfoTest, UpdateWithNoModification) {
AccountInfo info;
info.account_id = info.gaia = info.email = "test_id";
@@ -69,7 +70,7 @@ TEST_F(AccountInfoTest, UpdateWithNoModification) {
AccountInfo other;
other.account_id = "test_id";
- other.gaia = other.email = "test_other_id";
+ other.gaia = other.email = "test_id";
other.is_child_account = false;
EXPECT_FALSE(info.UpdateWith(other));
@@ -95,3 +96,37 @@ TEST_F(AccountInfoTest, UpdateWithSuccessfulUpdate) {
EXPECT_EQ("test_name", info.given_name);
EXPECT_TRUE(info.is_child_account);
}
+
+// Tests that UpdateWith() sets default values for hosted_domain and
+// picture_url if the properties are unset.
+TEST_F(AccountInfoTest, UpdateWithDefaultValues) {
+ AccountInfo info;
+ info.account_id = info.gaia = info.email = "test_id";
+
+ AccountInfo other;
+ other.account_id = "test_id";
+ other.hosted_domain = kNoHostedDomainFound;
+ other.picture_url = kNoPictureURLFound;
+
+ EXPECT_TRUE(info.UpdateWith(other));
+ EXPECT_EQ(kNoHostedDomainFound, info.hosted_domain);
+ EXPECT_EQ(kNoPictureURLFound, info.picture_url);
+}
+
+// Tests that UpdateWith() ignores default values for hosted_domain and
+// picture_url if they are already set.
+TEST_F(AccountInfoTest, UpdateWithDefaultValuesNoOverride) {
+ AccountInfo info;
+ info.account_id = info.gaia = info.email = "test_id";
+ info.hosted_domain = "test_domain";
+ info.picture_url = "test_url";
+
+ AccountInfo other;
+ other.account_id = "test_id";
+ other.hosted_domain = kNoHostedDomainFound;
+ other.picture_url = kNoPictureURLFound;
+
+ EXPECT_FALSE(info.UpdateWith(other));
+ EXPECT_EQ("test_domain", info.hosted_domain);
+ EXPECT_EQ("test_url", info.picture_url);
+}
diff --git a/chromium/components/signin/core/browser/account_info_util.cc b/chromium/components/signin/core/browser/account_info_util.cc
new file mode 100644
index 00000000000..878adeb5f62
--- /dev/null
+++ b/chromium/components/signin/core/browser/account_info_util.cc
@@ -0,0 +1,73 @@
+// Copyright 2019 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 "components/signin/core/browser/account_info_util.h"
+
+#include "components/signin/core/browser/account_info.h"
+
+namespace {
+// Keys used to store the different values in the JSON dictionary received
+// from gaia server.
+const char kGaiaIdKey[] = "id";
+const char kEmailKey[] = "email";
+const char kHostedDomainKey[] = "hd";
+const char kFullNameKey[] = "name";
+const char kGivenNameKey[] = "given_name";
+const char kLocaleKey[] = "locale";
+const char kPictureUrlKey[] = "picture";
+} // namespace
+
+base::Optional<AccountInfo> AccountInfoFromUserInfo(
+ const base::Value& user_info) {
+ if (!user_info.is_dict())
+ return base::nullopt;
+
+ // Both |gaia_id| and |email| are required value in the JSON reply, so
+ // return empty result if any is missing.
+ const base::Value* gaia_id_value =
+ user_info.FindKeyOfType(kGaiaIdKey, base::Value::Type::STRING);
+ if (!gaia_id_value)
+ return base::nullopt;
+
+ const base::Value* email_value =
+ user_info.FindKeyOfType(kEmailKey, base::Value::Type::STRING);
+ if (!email_value)
+ return base::nullopt;
+
+ AccountInfo account_info;
+ account_info.email = email_value->GetString();
+ account_info.gaia = gaia_id_value->GetString();
+
+ // All other fields are optional, some with default values.
+ const base::Value* hosted_domain_value =
+ user_info.FindKeyOfType(kHostedDomainKey, base::Value::Type::STRING);
+ if (hosted_domain_value && !hosted_domain_value->GetString().empty())
+ account_info.hosted_domain = hosted_domain_value->GetString();
+ else
+ account_info.hosted_domain = kNoHostedDomainFound;
+
+ const base::Value* full_name_value =
+ user_info.FindKeyOfType(kFullNameKey, base::Value::Type::STRING);
+ if (full_name_value)
+ account_info.full_name = full_name_value->GetString();
+
+ const base::Value* given_name_value =
+ user_info.FindKeyOfType(kGivenNameKey, base::Value::Type::STRING);
+ if (given_name_value)
+ account_info.given_name = given_name_value->GetString();
+
+ const base::Value* locale_value =
+ user_info.FindKeyOfType(kLocaleKey, base::Value::Type::STRING);
+ if (locale_value)
+ account_info.locale = locale_value->GetString();
+
+ const base::Value* picture_url_value =
+ user_info.FindKeyOfType(kPictureUrlKey, base::Value::Type::STRING);
+ if (picture_url_value && !picture_url_value->GetString().empty())
+ account_info.picture_url = picture_url_value->GetString();
+ else
+ account_info.picture_url = kNoPictureURLFound;
+
+ return account_info;
+}
diff --git a/chromium/components/signin/core/browser/account_info_util.h b/chromium/components/signin/core/browser/account_info_util.h
new file mode 100644
index 00000000000..fb2058a6674
--- /dev/null
+++ b/chromium/components/signin/core/browser/account_info_util.h
@@ -0,0 +1,17 @@
+// Copyright 2019 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 COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_INFO_UTIL_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_INFO_UTIL_H_
+
+#include "base/optional.h"
+#include "base/values.h"
+#include "components/signin/core/browser/account_info.h"
+
+// Builds an AccountInfo from the JSON data returned by the gaia servers (the
+// data should have been converted to base::Value), if possible.
+base::Optional<AccountInfo> AccountInfoFromUserInfo(
+ const base::Value& user_info);
+
+#endif // COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_INFO_UTIL_H_
diff --git a/chromium/components/signin/core/browser/account_info_util_unittest.cc b/chromium/components/signin/core/browser/account_info_util_unittest.cc
new file mode 100644
index 00000000000..da0c76f172f
--- /dev/null
+++ b/chromium/components/signin/core/browser/account_info_util_unittest.cc
@@ -0,0 +1,158 @@
+// Copyright 2019 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 "components/signin/core/browser/account_info_util.h"
+
+#include "components/signin/core/browser/account_info.h"
+#include "testing/platform_test.h"
+
+namespace {
+// Returns a base::Value corresponding to the user info as would be returned
+// by gaia server with provided values (if null is passed for a value, it will
+// not be set in the returned user_info object).
+base::Value CreateUserInfoWithValues(const char* email,
+ const char* gaia,
+ const char* hosted_domain,
+ const char* full_name,
+ const char* given_name,
+ const char* locale,
+ const char* picture_url) {
+ base::Value user_info(base::Value::Type::DICTIONARY);
+ if (email)
+ user_info.SetKey("email", base::Value(email));
+
+ if (gaia)
+ user_info.SetKey("id", base::Value(gaia));
+
+ if (hosted_domain)
+ user_info.SetKey("hd", base::Value(hosted_domain));
+
+ if (full_name)
+ user_info.SetKey("name", base::Value(full_name));
+
+ if (given_name)
+ user_info.SetKey("given_name", base::Value(given_name));
+
+ if (locale)
+ user_info.SetKey("locale", base::Value(locale));
+
+ if (picture_url)
+ user_info.SetKey("picture", base::Value(picture_url));
+
+ return user_info;
+}
+} // namespace
+
+using AccountInfoUtilTest = PlatformTest;
+
+// Tests that AccountInfoFromUserInfo returns an AccountInfo with the value
+// extracted from the passed base::Value.
+TEST_F(AccountInfoUtilTest, FromUserInfo) {
+ base::Optional<AccountInfo> maybe_account_info =
+ AccountInfoFromUserInfo(CreateUserInfoWithValues(
+ /*email=*/"user@example.com", /*gaia=*/"gaia_id_user_example_com",
+ /*hosted_domain=*/"example.com", /*full_name=*/"full name",
+ /*given_name=*/"given name", /*locale=*/"locale",
+ /*picture_url=*/"https://example.com/picture/user"));
+
+ ASSERT_TRUE(maybe_account_info.has_value());
+
+ AccountInfo& account_info = maybe_account_info.value();
+ ASSERT_EQ(account_info.email, "user@example.com");
+ ASSERT_EQ(account_info.gaia, "gaia_id_user_example_com");
+ ASSERT_EQ(account_info.hosted_domain, "example.com");
+ ASSERT_EQ(account_info.full_name, "full name");
+ ASSERT_EQ(account_info.given_name, "given name");
+ ASSERT_EQ(account_info.locale, "locale");
+ ASSERT_EQ(account_info.picture_url, "https://example.com/picture/user");
+}
+
+// Tests that AccountInfoFromUserInfo returns an AccountInfo with empty or
+// default values if no fields are set in the user_info.
+TEST_F(AccountInfoUtilTest, FromUserInfo_EmptyValues) {
+ base::Optional<AccountInfo> maybe_account_info =
+ AccountInfoFromUserInfo(CreateUserInfoWithValues(
+ /*email=*/"", /*gaia=*/"", /*hosted_domain=*/"", /*full_name=*/"",
+ /*given_name=*/"", /*locale=*/"", /*picture_url=*/""));
+
+ ASSERT_TRUE(maybe_account_info.has_value());
+
+ AccountInfo& account_info = maybe_account_info.value();
+ ASSERT_EQ(account_info.email, std::string());
+ ASSERT_EQ(account_info.gaia, std::string());
+ ASSERT_EQ(account_info.hosted_domain, kNoHostedDomainFound);
+ ASSERT_EQ(account_info.full_name, std::string());
+ ASSERT_EQ(account_info.given_name, std::string());
+ ASSERT_EQ(account_info.locale, std::string());
+ ASSERT_EQ(account_info.picture_url, kNoPictureURLFound);
+}
+
+// Tests that AccountInfoFromUserInfo returns an AccountInfo with the value
+// extracted from the passed base::Value, with default value for |hosted_domain|
+// if missing.
+TEST_F(AccountInfoUtilTest, FromUserInfo_NoHostedDomain) {
+ base::Optional<AccountInfo> maybe_account_info =
+ AccountInfoFromUserInfo(CreateUserInfoWithValues(
+ /*email=*/"user@example.com", /*gaia=*/"gaia_id_user_example_com",
+ /*hosted_domain=*/nullptr, /*full_name=*/"full name",
+ /*given_name=*/"given name", /*locale=*/"locale",
+ /*picture_url=*/"https://example.com/picture/user"));
+
+ ASSERT_TRUE(maybe_account_info.has_value());
+
+ AccountInfo& account_info = maybe_account_info.value();
+ ASSERT_EQ(account_info.hosted_domain, kNoHostedDomainFound);
+}
+
+// Tests that AccountInfoFromUserInfo returns an AccountInfo with the value
+// extracted from the passed base::Value, with default value for |picture_url|
+// if missing.
+TEST_F(AccountInfoUtilTest, FromUserInfo_NoPictureUrl) {
+ base::Optional<AccountInfo> maybe_account_info =
+ AccountInfoFromUserInfo(CreateUserInfoWithValues(
+ /*email=*/"user@example.com", /*gaia=*/"gaia_id_user_example_com",
+ /*hosted_domain=*/"example.com", /*full_name=*/"full name",
+ /*given_name=*/"given name", /*locale=*/"locale",
+ /*picture_url=*/nullptr));
+
+ ASSERT_TRUE(maybe_account_info.has_value());
+
+ AccountInfo& account_info = maybe_account_info.value();
+ ASSERT_EQ(account_info.picture_url, kNoPictureURLFound);
+}
+
+// Tests that if AccountInfoFromUserInfo fails if the value passed has no
+// value for |email|.
+TEST_F(AccountInfoUtilTest, FromUserInfo_NoEmail) {
+ base::Optional<AccountInfo> maybe_account_info =
+ AccountInfoFromUserInfo(CreateUserInfoWithValues(
+ /*email=*/nullptr, /*gaia=*/"gaia_id_user_example_com",
+ /*hosted_domain=*/"example.com", /*full_name=*/"full name",
+ /*given_name=*/"given name", /*locale=*/"locale",
+ /*picture_url=*/"https://example.com/picture/user"));
+
+ EXPECT_FALSE(maybe_account_info.has_value());
+}
+
+// Tests that if AccountInfoFromUserInfo fails if the value passed has no
+// value for |gaia|.
+TEST_F(AccountInfoUtilTest, FromUserInfo_NoGaiaId) {
+ base::Optional<AccountInfo> maybe_account_info =
+ AccountInfoFromUserInfo(CreateUserInfoWithValues(
+ /*email=*/"user@example.com", /*gaia=*/nullptr,
+ /*hosted_domain=*/"example.com", /*full_name=*/"full name",
+ /*given_name=*/"given name", /*locale=*/"locale",
+ /*picture_url=*/"https://example.com/picture/user"));
+
+ EXPECT_FALSE(maybe_account_info.has_value());
+}
+
+// Tests that if AccountInfoFromUserInfo fails if the value passed is not a
+// dictionary.
+TEST_F(AccountInfoUtilTest, FromUserInfo_NotADictionary) {
+ base::Optional<AccountInfo> maybe_account_info =
+ AccountInfoFromUserInfo(base::Value("not a dictionary"));
+
+ EXPECT_FALSE(maybe_account_info.has_value());
+}
diff --git a/chromium/components/signin/core/browser/account_investigator.cc b/chromium/components/signin/core/browser/account_investigator.cc
index eb3d15fec8b..239b372330e 100644
--- a/chromium/components/signin/core/browser/account_investigator.cc
+++ b/chromium/components/signin/core/browser/account_investigator.cc
@@ -17,7 +17,7 @@
#include "components/signin/core/browser/signin_pref_names.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/google_service_auth_error.h"
-#include "services/identity/public/cpp/identity_manager.h"
+#include "services/identity/public/cpp/accounts_in_cookie_jar_info.h"
using base::Time;
using base::TimeDelta;
@@ -42,12 +42,9 @@ const TimeDelta AccountInvestigator::kPeriodicReportingInterval =
TimeDelta::FromDays(1);
AccountInvestigator::AccountInvestigator(
- GaiaCookieManagerService* cookie_service,
PrefService* pref_service,
identity::IdentityManager* identity_manager)
- : cookie_service_(cookie_service),
- pref_service_(pref_service),
- identity_manager_(identity_manager) {}
+ : pref_service_(pref_service), identity_manager_(identity_manager) {}
AccountInvestigator::~AccountInvestigator() {}
@@ -59,7 +56,7 @@ void AccountInvestigator::RegisterPrefs(PrefRegistrySimple* registry) {
}
void AccountInvestigator::Initialize() {
- cookie_service_->AddObserver(this);
+ identity_manager_->AddObserver(this);
previously_authenticated_ = identity_manager_->HasPrimaryAccount();
Time previous = Time::FromDoubleT(
@@ -72,7 +69,7 @@ void AccountInvestigator::Initialize() {
}
void AccountInvestigator::Shutdown() {
- cookie_service_->RemoveObserver(this);
+ identity_manager_->RemoveObserver(this);
timer_.Stop();
}
@@ -84,6 +81,14 @@ void AccountInvestigator::OnAddAccountToCookieCompleted(
// called serveral times.
}
+void AccountInvestigator::OnAccountsInCookieUpdated(
+ const identity::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
+ const GoogleServiceAuthError& error) {
+ OnGaiaAccountsInCookieUpdated(accounts_in_cookie_jar_info.signed_in_accounts,
+ accounts_in_cookie_jar_info.signed_out_accounts,
+ error);
+}
+
void AccountInvestigator::OnGaiaAccountsInCookieUpdated(
const std::vector<ListedAccount>& signed_in_accounts,
const std::vector<ListedAccount>& signed_out_accounts,
@@ -186,8 +191,8 @@ AccountRelation AccountInvestigator::DiscernRelation(
} else if (signed_out_match_iter != signed_out_accounts.end()) {
if (signed_in_accounts.empty()) {
return signed_out_accounts.size() == 1
- ? AccountRelation::NO_SIGNED_IN_SINGLE_SIGNED_OUT_MATCH
- : AccountRelation::NO_SIGNED_IN_ONE_OF_SIGNED_OUT_MATCH;
+ ? AccountRelation::NO_SIGNED_IN_SINGLE_SIGNED_OUT_MATCH
+ : AccountRelation::NO_SIGNED_IN_ONE_OF_SIGNED_OUT_MATCH;
} else {
return AccountRelation::WITH_SIGNED_IN_ONE_OF_SIGNED_OUT_MATCH;
}
@@ -199,10 +204,11 @@ AccountRelation AccountInvestigator::DiscernRelation(
}
void AccountInvestigator::TryPeriodicReport() {
- std::vector<ListedAccount> signed_in_accounts, signed_out_accounts;
- if (cookie_service_->ListAccounts(&signed_in_accounts,
- &signed_out_accounts)) {
- DoPeriodicReport(signed_in_accounts, signed_out_accounts);
+ auto accounts_in_cookie_jar_info =
+ identity_manager_->GetAccountsInCookieJar();
+ if (accounts_in_cookie_jar_info.accounts_are_fresh) {
+ DoPeriodicReport(accounts_in_cookie_jar_info.signed_in_accounts,
+ accounts_in_cookie_jar_info.signed_out_accounts);
} else {
periodic_pending_ = true;
}
@@ -235,8 +241,7 @@ void AccountInvestigator::SharedCookieJarReport(
int signed_in_count = signed_in_accounts.size();
int signed_out_count = signed_out_accounts.size();
- signin_metrics::LogCookieJarCounts(signed_in_count,
- signed_out_count,
+ signin_metrics::LogCookieJarCounts(signed_in_count, signed_out_count,
signed_in_count + signed_out_count, type);
if (identity_manager_->HasPrimaryAccount()) {
diff --git a/chromium/components/signin/core/browser/account_investigator.h b/chromium/components/signin/core/browser/account_investigator.h
index 6fb94997788..dd6b6661f7a 100644
--- a/chromium/components/signin/core/browser/account_investigator.h
+++ b/chromium/components/signin/core/browser/account_investigator.h
@@ -11,10 +11,9 @@
#include "base/macros.h"
#include "base/timer/timer.h"
#include "components/keyed_service/core/keyed_service.h"
-#include "components/signin/core/browser/gaia_cookie_manager_service.h"
+#include "services/identity/public/cpp/identity_manager.h"
struct AccountInfo;
-class GaiaCookieManagerService;
class PrefRegistrySimple;
class PrefService;
@@ -23,8 +22,8 @@ class Time;
} // namespace base
namespace identity {
-class IdentityManager;
-}
+struct AccountsInCookieJarInfo;
+} // namespace identity
namespace signin_metrics {
enum class AccountRelation;
@@ -36,15 +35,14 @@ enum class ReportingType;
// is to watch for changes in relation between Chrome and content area accounts
// and emit metrics about their relation.
class AccountInvestigator : public KeyedService,
- public GaiaCookieManagerService::Observer {
+ public identity::IdentityManager::Observer {
public:
// The targeted interval to perform periodic reporting. If chrome is not
// active at the end of an interval, reporting will be done as soon as
// possible.
static const base::TimeDelta kPeriodicReportingInterval;
- AccountInvestigator(GaiaCookieManagerService* cookie_service,
- PrefService* pref_service,
+ AccountInvestigator(PrefService* pref_service,
identity::IdentityManager* identity_manager);
~AccountInvestigator() override;
@@ -56,14 +54,20 @@ class AccountInvestigator : public KeyedService,
// KeyedService:
void Shutdown() override;
- // GaiaCookieManagerService::Observer:
+ // identity::IdentityManager::Observer:
void OnAddAccountToCookieCompleted(
const std::string& account_id,
const GoogleServiceAuthError& error) override;
+ void OnAccountsInCookieUpdated(
+ const identity::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
+ const GoogleServiceAuthError& error) override;
+
+ // Internal implementation of OnAccountsInCookieUpdated. It is public given
+ // that it is called directly by unittests.
void OnGaiaAccountsInCookieUpdated(
const std::vector<gaia::ListedAccount>& signed_in_accounts,
const std::vector<gaia::ListedAccount>& signed_out_accounts,
- const GoogleServiceAuthError& error) override;
+ const GoogleServiceAuthError& error);
private:
friend class AccountInvestigatorTest;
@@ -114,7 +118,6 @@ class AccountInvestigator : public KeyedService,
const std::vector<gaia::ListedAccount>& signed_out_accounts,
signin_metrics::ReportingType type);
- GaiaCookieManagerService* cookie_service_;
PrefService* pref_service_;
identity::IdentityManager* identity_manager_;
diff --git a/chromium/components/signin/core/browser/account_investigator_unittest.cc b/chromium/components/signin/core/browser/account_investigator_unittest.cc
index b72205b02c9..d8eaca6d908 100644
--- a/chromium/components/signin/core/browser/account_investigator_unittest.cc
+++ b/chromium/components/signin/core/browser/account_investigator_unittest.cc
@@ -8,20 +8,14 @@
#include <string>
#include <vector>
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_task_environment.h"
#include "base/timer/timer.h"
#include "components/prefs/pref_registry_simple.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
-#include "components/signin/core/browser/fake_signin_manager.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_metrics.h"
#include "components/signin/core/browser/signin_pref_names.h"
-#include "components/signin/core/browser/test_signin_client.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
-#include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "services/identity/public/cpp/identity_test_environment.h"
@@ -37,38 +31,18 @@ using signin_metrics::ReportingType;
class AccountInvestigatorTest : public testing::Test {
protected:
AccountInvestigatorTest()
- : signin_client_(&prefs_),
- token_service_(&prefs_,
- std::make_unique<FakeOAuth2TokenServiceDelegate>()),
- signin_manager_(&signin_client_,
- &token_service_,
- &account_tracker_service_,
- nullptr),
- gaia_cookie_manager_service_(&token_service_, &signin_client_),
- identity_test_env_(&account_tracker_service_,
- &token_service_,
- &signin_manager_,
- &gaia_cookie_manager_service_),
- investigator_(&gaia_cookie_manager_service_,
- &prefs_,
- identity_test_env_.identity_manager()) {
- AccountTrackerService::RegisterPrefs(prefs_.registry());
+ : identity_test_env_(&test_url_loader_factory_, &prefs_),
+ investigator_(&prefs_, identity_test_env_.identity_manager()) {
AccountInvestigator::RegisterPrefs(prefs_.registry());
- SigninManagerBase::RegisterProfilePrefs(prefs_.registry());
- account_tracker_service_.Initialize(&prefs_, base::FilePath());
}
~AccountInvestigatorTest() override { investigator_.Shutdown(); }
- FakeSigninManager* signin_manager() { return &signin_manager_; }
identity::IdentityTestEnvironment* identity_test_env() {
return &identity_test_env_;
}
PrefService* pref_service() { return &prefs_; }
AccountInvestigator* investigator() { return &investigator_; }
- FakeGaiaCookieManagerService* cookie_manager_service() {
- return &gaia_cookie_manager_service_;
- }
// Wrappers to invoke private methods through friend class.
TimeDelta Delay(const Time previous,
@@ -82,15 +56,14 @@ class AccountInvestigatorTest : public testing::Test {
signed_out_accounts);
}
AccountRelation Relation(
- const AccountInfo& info,
+ const AccountInfo& account_info,
const std::vector<ListedAccount>& signed_in_accounts,
const std::vector<ListedAccount>& signed_out_accounts) {
- return AccountInvestigator::DiscernRelation(info,
- signed_in_accounts,
- signed_out_accounts);
+ return AccountInvestigator::DiscernRelation(
+ account_info, signed_in_accounts, signed_out_accounts);
}
- void SharedReport(const std::vector<gaia::ListedAccount>& signed_in_accounts,
- const std::vector<gaia::ListedAccount>& signed_out_accounts,
+ void SharedReport(const std::vector<ListedAccount>& signed_in_accounts,
+ const std::vector<ListedAccount>& signed_out_accounts,
const Time now,
const ReportingType type) {
investigator_.SharedCookieJarReport(signed_in_accounts, signed_out_accounts,
@@ -110,8 +83,7 @@ class AccountInvestigatorTest : public testing::Test {
const AccountRelation expected) {
HistogramTester histogram_tester;
investigator_.SignedInAccountRelationReport(signed_in_accounts,
- signed_out_accounts,
- type);
+ signed_out_accounts, type);
ExpectRelationReport(type, histogram_tester, expected);
}
@@ -162,13 +134,9 @@ class AccountInvestigatorTest : public testing::Test {
private:
// Timer needs a message loop.
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment task_environment_;
sync_preferences::TestingPrefServiceSyncable prefs_;
- AccountTrackerService account_tracker_service_;
- TestSigninClient signin_client_;
- FakeProfileOAuth2TokenService token_service_;
- FakeSigninManager signin_manager_;
- FakeGaiaCookieManagerService gaia_cookie_manager_service_;
+ network::TestURLLoaderFactory test_url_loader_factory_;
identity::IdentityTestEnvironment identity_test_env_;
AccountInvestigator investigator_;
std::map<ReportingType, std::string> suffix_ = {
@@ -184,25 +152,30 @@ ListedAccount Account(const std::string& id) {
return account;
}
-AccountInfo Info(const std::string& id) {
- AccountInfo info;
- info.account_id = id;
- return info;
+AccountInfo ToAccountInfo(ListedAccount account) {
+ AccountInfo account_info;
+ account_info.account_id = account.id;
+ account_info.gaia = account.gaia_id;
+ account_info.email = account.email;
+ return account_info;
}
// NOTE: IdentityTestEnvironment uses a prefix for generating gaia IDs:
// "gaia_id_for_". For this reason, the tests prefix expected account IDs
// used so that there is a match.
-const std::vector<ListedAccount> no_accounts{};
-const std::vector<ListedAccount> just_one{Account("gaia_id_for_1_mail.com")};
-const std::vector<ListedAccount> just_two{Account("gaia_id_for_2_mail.com")};
-const std::vector<ListedAccount> both{Account("gaia_id_for_1_mail.com"),
- Account("gaia_id_for_2_mail.com")};
-const std::vector<ListedAccount> both_reversed{
- Account("gaia_id_for_2_mail.com"), Account("gaia_id_for_1_mail.com")};
+const std::string kGaiaId1 = identity::GetTestGaiaIdForEmail("1@mail.com");
+const std::string kGaiaId2 = identity::GetTestGaiaIdForEmail("2@mail.com");
+const std::string kGaiaId3 = identity::GetTestGaiaIdForEmail("3@mail.com");
-const AccountInfo one(Info("gaia_id_for_1_mail.com"));
-const AccountInfo three(Info("gaia_id_for_3_mail.com"));
+const ListedAccount one(Account(kGaiaId1));
+const ListedAccount two(Account(kGaiaId2));
+const ListedAccount three(Account(kGaiaId3));
+
+const std::vector<ListedAccount> no_accounts{};
+const std::vector<ListedAccount> just_one{one};
+const std::vector<ListedAccount> just_two{two};
+const std::vector<ListedAccount> both{one, two};
+const std::vector<ListedAccount> both_reversed{two, one};
TEST_F(AccountInvestigatorTest, CalculatePeriodicDelay) {
const Time epoch;
@@ -233,25 +206,25 @@ TEST_F(AccountInvestigatorTest, HashAccounts) {
TEST_F(AccountInvestigatorTest, DiscernRelation) {
EXPECT_EQ(AccountRelation::EMPTY_COOKIE_JAR,
- Relation(one, no_accounts, no_accounts));
+ Relation(ToAccountInfo(one), no_accounts, no_accounts));
EXPECT_EQ(AccountRelation::SINGLE_SIGNED_IN_MATCH_NO_SIGNED_OUT,
- Relation(one, just_one, no_accounts));
+ Relation(ToAccountInfo(one), just_one, no_accounts));
EXPECT_EQ(AccountRelation::SINGLE_SINGED_IN_MATCH_WITH_SIGNED_OUT,
- Relation(one, just_one, just_two));
+ Relation(ToAccountInfo(one), just_one, just_two));
EXPECT_EQ(AccountRelation::WITH_SIGNED_IN_NO_MATCH,
- Relation(one, just_two, no_accounts));
+ Relation(ToAccountInfo(one), just_two, no_accounts));
EXPECT_EQ(AccountRelation::ONE_OF_SIGNED_IN_MATCH_ANY_SIGNED_OUT,
- Relation(one, both, just_one));
+ Relation(ToAccountInfo(one), both, just_one));
EXPECT_EQ(AccountRelation::ONE_OF_SIGNED_IN_MATCH_ANY_SIGNED_OUT,
- Relation(one, both, no_accounts));
+ Relation(ToAccountInfo(one), both, no_accounts));
EXPECT_EQ(AccountRelation::NO_SIGNED_IN_ONE_OF_SIGNED_OUT_MATCH,
- Relation(one, no_accounts, both));
+ Relation(ToAccountInfo(one), no_accounts, both));
EXPECT_EQ(AccountRelation::NO_SIGNED_IN_SINGLE_SIGNED_OUT_MATCH,
- Relation(one, no_accounts, just_one));
+ Relation(ToAccountInfo(one), no_accounts, just_one));
EXPECT_EQ(AccountRelation::WITH_SIGNED_IN_ONE_OF_SIGNED_OUT_MATCH,
- Relation(one, just_two, just_one));
+ Relation(ToAccountInfo(one), just_two, just_one));
EXPECT_EQ(AccountRelation::NO_SIGNED_IN_WITH_SIGNED_OUT_NO_MATCH,
- Relation(three, no_accounts, both));
+ Relation(ToAccountInfo(three), no_accounts, both));
}
TEST_F(AccountInvestigatorTest, SignedInAccountRelationReport) {
@@ -330,7 +303,7 @@ TEST_F(AccountInvestigatorTest,
// Simulate a sign out of the content area.
const HistogramTester histogram_tester2;
investigator()->OnGaiaAccountsInCookieUpdated(
- no_accounts, just_one, GoogleServiceAuthError::AuthErrorNone());
+ no_accounts, just_one, GoogleServiceAuthError::AuthErrorNone());
const AccountRelation expected_relation =
AccountRelation::NO_SIGNED_IN_SINGLE_SIGNED_OUT_MATCH;
ExpectSharedReportHistograms(ReportingType::ON_CHANGE, histogram_tester2,
@@ -359,22 +332,23 @@ TEST_F(AccountInvestigatorTest, InitializeSignedIn) {
TEST_F(AccountInvestigatorTest, TryPeriodicReportStale) {
investigator()->Initialize();
- cookie_manager_service()->set_list_accounts_stale_for_testing(true);
- cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
const HistogramTester histogram_tester;
TryPeriodicReport();
EXPECT_TRUE(*periodic_pending());
EXPECT_EQ(0u, histogram_tester.GetTotalCountsForPrefix("Signin.").size());
- base::RunLoop().RunUntilIdle();
+ std::string email("f@bar.com");
+ identity_test_env()->SetCookieAccounts(
+ {{email, identity::GetTestGaiaIdForEmail(email)}});
+
EXPECT_FALSE(*periodic_pending());
ExpectSharedReportHistograms(ReportingType::PERIODIC, histogram_tester,
nullptr, 1, 0, 1, nullptr, false);
}
TEST_F(AccountInvestigatorTest, TryPeriodicReportEmpty) {
- cookie_manager_service()->set_list_accounts_stale_for_testing(false);
+ identity_test_env()->SetFreshnessOfAccountsInGaiaCookie(false);
const HistogramTester histogram_tester;
TryPeriodicReport();
diff --git a/chromium/components/signin/core/browser/account_reconcilor.cc b/chromium/components/signin/core/browser/account_reconcilor.cc
index 7113c3b1898..0393eb4ddda 100644
--- a/chromium/components/signin/core/browser/account_reconcilor.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor.cc
@@ -21,14 +21,13 @@
#include "build/build_config.h"
#include "components/signin/core/browser/account_consistency_method.h"
#include "components/signin/core/browser/account_reconcilor_delegate.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_buildflags.h"
#include "components/signin/core/browser/signin_client.h"
#include "components/signin/core/browser/signin_metrics.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
-#include "services/identity/public/cpp/identity_manager.h"
+#include "services/identity/public/cpp/accounts_mutator.h"
using signin::AccountReconcilorDelegate;
@@ -72,7 +71,7 @@ std::vector<gaia::ListedAccount> FilterUnverifiedAccounts(
// Revokes tokens for all accounts in chrome_accounts but the primary account.
// Returns true if tokens were revoked, and false if the function did nothing.
bool RevokeAllSecondaryTokens(
- ProfileOAuth2TokenService* token_service,
+ identity::IdentityManager* identity_manager,
signin::AccountReconcilorDelegate::RevokeTokenOption revoke_option,
const std::string& primary_account,
bool is_account_consistency_enforced,
@@ -81,13 +80,16 @@ bool RevokeAllSecondaryTokens(
if (revoke_option ==
AccountReconcilorDelegate::RevokeTokenOption::kDoNotRevoke)
return false;
- for (const std::string& account : token_service->GetAccounts()) {
+ for (const AccountInfo& account_info :
+ identity_manager->GetAccountsWithRefreshTokens()) {
+ std::string account(account_info.account_id);
if (account == primary_account)
continue;
bool should_revoke = false;
switch (revoke_option) {
case AccountReconcilorDelegate::RevokeTokenOption::kRevokeIfInError:
- if (token_service->RefreshTokenHasError(account)) {
+ if (identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
+ account)) {
VLOG(1) << "Revoke token for " << account;
should_revoke = true;
}
@@ -105,8 +107,10 @@ bool RevokeAllSecondaryTokens(
if (should_revoke) {
token_revoked = true;
VLOG(1) << "Revoke token for " << account;
- if (is_account_consistency_enforced)
- token_service->RevokeCredentials(account, source);
+ if (is_account_consistency_enforced) {
+ auto* accounts_mutator = identity_manager->GetAccountsMutator();
+ accounts_mutator->RemoveAccount(account, source);
+ }
}
}
return token_revoked;
@@ -154,14 +158,15 @@ std::string PickFirstGaiaAccount(
} // namespace
AccountReconcilor::Lock::Lock(AccountReconcilor* reconcilor)
- : reconcilor_(reconcilor) {
+ : reconcilor_(reconcilor->weak_factory_.GetWeakPtr()) {
DCHECK(reconcilor_);
reconcilor_->IncrementLockCount();
}
AccountReconcilor::Lock::~Lock() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- reconcilor_->DecrementLockCount();
+ if (reconcilor_)
+ reconcilor_->DecrementLockCount();
}
AccountReconcilor::ScopedSyncedDataDeletion::ScopedSyncedDataDeletion(
@@ -180,23 +185,22 @@ AccountReconcilor::ScopedSyncedDataDeletion::~ScopedSyncedDataDeletion() {
}
AccountReconcilor::AccountReconcilor(
- ProfileOAuth2TokenService* token_service,
identity::IdentityManager* identity_manager,
SigninClient* client,
GaiaCookieManagerService* cookie_manager_service,
std::unique_ptr<signin::AccountReconcilorDelegate> delegate)
: delegate_(std::move(delegate)),
- token_service_(token_service),
identity_manager_(identity_manager),
client_(client),
cookie_manager_service_(cookie_manager_service),
- registered_with_token_service_(false),
+ registered_with_identity_manager_(false),
registered_with_cookie_manager_service_(false),
registered_with_content_settings_(false),
is_reconcile_started_(false),
first_execution_(true),
error_during_last_reconcile_(GoogleServiceAuthError::AuthErrorNone()),
reconcile_is_noop_(true),
+ set_accounts_in_progress_(false),
chrome_accounts_changed_(false),
account_reconcilor_lock_count_(0),
reconcile_on_unblock_(false),
@@ -211,7 +215,7 @@ AccountReconcilor::AccountReconcilor(
AccountReconcilor::~AccountReconcilor() {
VLOG(1) << "AccountReconcilor::~AccountReconcilor";
// Make sure shutdown was called first.
- DCHECK(!registered_with_token_service_);
+ DCHECK(!registered_with_identity_manager_);
DCHECK(!registered_with_cookie_manager_service_);
}
@@ -221,7 +225,7 @@ void AccountReconcilor::Initialize(bool start_reconcile_if_tokens_available) {
EnableReconcile();
// Start a reconcile if the tokens are already loaded.
- if (start_reconcile_if_tokens_available && IsTokenServiceReady())
+ if (start_reconcile_if_tokens_available && IsIdentityManagerReady())
StartReconcile();
}
}
@@ -236,13 +240,13 @@ void AccountReconcilor::EnableReconcile() {
DCHECK(delegate_->IsReconcileEnabled());
RegisterWithCookieManagerService();
RegisterWithContentSettings();
- RegisterWithTokenService();
+ RegisterWithIdentityManager();
}
void AccountReconcilor::DisableReconcile(bool logout_all_accounts) {
AbortReconcile();
UnregisterWithCookieManagerService();
- UnregisterWithTokenService();
+ UnregisterWithIdentityManager();
UnregisterWithContentSettings();
if (logout_all_accounts)
@@ -276,25 +280,25 @@ void AccountReconcilor::UnregisterWithContentSettings() {
registered_with_content_settings_ = false;
}
-void AccountReconcilor::RegisterWithTokenService() {
- VLOG(1) << "AccountReconcilor::RegisterWithTokenService";
+void AccountReconcilor::RegisterWithIdentityManager() {
+ VLOG(1) << "AccountReconcilor::RegisterWithIdentityManager";
// During re-auth, the reconcilor will get a callback about successful signin
// even when the profile is already connected. Avoid re-registering
// with the token service since this will DCHECK.
- if (registered_with_token_service_)
+ if (registered_with_identity_manager_)
return;
- token_service_->AddObserver(this);
- registered_with_token_service_ = true;
+ identity_manager_->AddObserver(this);
+ registered_with_identity_manager_ = true;
}
-void AccountReconcilor::UnregisterWithTokenService() {
- VLOG(1) << "AccountReconcilor::UnregisterWithTokenService";
- if (!registered_with_token_service_)
+void AccountReconcilor::UnregisterWithIdentityManager() {
+ VLOG(1) << "AccountReconcilor::UnregisterWithIdentityManager";
+ if (!registered_with_identity_manager_)
return;
- token_service_->RemoveObserver(this);
- registered_with_token_service_ = false;
+ identity_manager_->RemoveObserver(this);
+ registered_with_identity_manager_ = false;
}
void AccountReconcilor::RegisterWithCookieManagerService() {
@@ -363,8 +367,8 @@ void AccountReconcilor::OnContentSettingChanged(
StartReconcile();
}
-void AccountReconcilor::OnEndBatchChanges() {
- VLOG(1) << "AccountReconcilor::OnEndBatchChanges. "
+void AccountReconcilor::OnEndBatchOfRefreshTokenStateChanges() {
+ VLOG(1) << "AccountReconcilor::OnEndBatchOfRefreshTokenStateChanges. "
<< "Reconcilor state: " << is_reconcile_started_;
// Remember that accounts have changed if a reconcile is already started.
chrome_accounts_changed_ = is_reconcile_started_;
@@ -375,8 +379,8 @@ void AccountReconcilor::OnRefreshTokensLoaded() {
StartReconcile();
}
-void AccountReconcilor::OnAuthErrorChanged(
- const std::string& account_id,
+void AccountReconcilor::OnErrorStateOfRefreshTokenUpdatedForAccount(
+ const AccountInfo& account_info,
const GoogleServiceAuthError& error) {
// Gaia cookies may be invalidated server-side and the client does not get any
// notification when this happens.
@@ -403,7 +407,6 @@ void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
void AccountReconcilor::PerformSetCookiesAction(
const signin::MultiloginParameters& parameters) {
reconcile_is_noop_ = false;
- is_reconcile_started_ = true;
VLOG(1) << "AccountReconcilor::PerformSetCookiesAction: "
<< base::JoinString(parameters.accounts_to_send, " ");
// TODO (https://crbug.com/890321): pass mode to GaiaCookieManagerService.
@@ -437,7 +440,7 @@ void AccountReconcilor::StartReconcile() {
}
// Do not reconcile if tokens are not loaded yet.
- if (!IsTokenServiceReady()) {
+ if (!IsIdentityManagerReady()) {
VLOG(1)
<< "AccountReconcilor::StartReconcile: token service *not* ready yet.";
return;
@@ -453,18 +456,18 @@ void AccountReconcilor::StartReconcile() {
reconcile_is_noop_ = true;
if (!timeout_.is_max()) {
- // Keep using base::Bind() until base::OnceCallback get supported by
- // base::OneShotTimer.
timer_->Start(FROM_HERE, timeout_,
base::BindOnce(&AccountReconcilor::HandleReconcileTimeout,
base::Unretained(this)));
}
const std::string& account_id = identity_manager_->GetPrimaryAccountId();
- if (token_service_->RefreshTokenHasError(account_id) &&
+ if (identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
+ account_id) &&
delegate_->ShouldAbortReconcileIfPrimaryHasError()) {
VLOG(1) << "AccountReconcilor::StartReconcile: primary has error, abort.";
- error_during_last_reconcile_ = token_service_->GetAuthError(account_id);
+ error_during_last_reconcile_ =
+ identity_manager_->GetErrorStateOfRefreshTokenForAccount(account_id);
AbortReconcile();
return;
}
@@ -483,9 +486,11 @@ void AccountReconcilor::FinishReconcileWithMultiloginEndpoint(
const std::vector<std::string>& chrome_accounts,
std::vector<gaia::ListedAccount>&& gaia_accounts) {
DCHECK(base::FeatureList::IsEnabled(kUseMultiloginEndpoint));
+ DCHECK(!set_accounts_in_progress_);
bool primary_has_error =
- token_service_->RefreshTokenHasError(primary_account);
+ identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
+ primary_account);
const signin::MultiloginParameters parameters_for_multilogin =
delegate_->CalculateParametersForMultilogin(
@@ -498,7 +503,9 @@ void AccountReconcilor::FinishReconcileWithMultiloginEndpoint(
// and any StartReconcile() calls that are made in the meantime will be
// aborted until OnSetAccountsInCookieCompleted is called and
// is_reconcile_started_ is set to false.
+ set_accounts_in_progress_ = true;
PerformSetCookiesAction(parameters_for_multilogin);
+ DCHECK(is_reconcile_started_);
} else {
OnSetAccountsInCookieCompleted(GoogleServiceAuthError::AuthErrorNone());
DCHECK(!is_reconcile_started_);
@@ -531,6 +538,18 @@ void AccountReconcilor::OnGaiaAccountsInCookieUpdated(
<< "Reconcilor's state is " << is_reconcile_started_ << ", "
<< "Error was " << error.ToString();
+ // If cookies change while the reconcilor is running, ignore the changes and
+ // let it complete. Adding accounts to the cookie will trigger new
+ // notifications anyway, and these will be handled in a new reconciliation
+ // cycle. See https://crbug.com/923716
+ if (IsMultiloginEndpointEnabled()) {
+ if (set_accounts_in_progress_)
+ return;
+ } else {
+ if (!add_to_cookie_.empty())
+ return;
+ }
+
if (error.state() != GoogleServiceAuthError::NONE) {
// We may have seen a series of errors during reconciliation. Delegates may
// rely on the severity of the last seen error (see |OnReconcileError|) and
@@ -562,12 +581,14 @@ void AccountReconcilor::OnGaiaAccountsInCookieUpdated(
AccountReconcilorDelegate::RevokeTokenOption revoke_option =
delegate_->ShouldRevokeSecondaryTokensBeforeReconcile(
verified_gaia_accounts);
- RevokeAllSecondaryTokens(token_service_, revoke_option, primary_account, true,
+ RevokeAllSecondaryTokens(identity_manager_, revoke_option, primary_account,
+ true,
signin_metrics::SourceForRefreshTokenOperation::
kAccountReconcilor_GaiaCookiesUpdated);
if (delegate_->ShouldAbortReconcileIfPrimaryHasError() &&
- token_service_->RefreshTokenHasError(primary_account)) {
+ identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
+ primary_account)) {
VLOG(1) << "Primary account has error, abort.";
DCHECK(is_reconcile_started_);
AbortReconcile();
@@ -591,17 +612,18 @@ void AccountReconcilor::OnGaiaCookieDeletedByUserAction() {
const std::string& primary_account = identity_manager_->GetPrimaryAccountId();
// Revoke secondary tokens.
RevokeAllSecondaryTokens(
- token_service_, AccountReconcilorDelegate::RevokeTokenOption::kRevoke,
+ identity_manager_, AccountReconcilorDelegate::RevokeTokenOption::kRevoke,
primary_account, /*account_consistency_enforced=*/true,
signin_metrics::SourceForRefreshTokenOperation::
kAccountReconcilor_GaiaCookiesDeletedByUser);
if (primary_account.empty())
return;
- if (token_service_->RefreshTokenHasError(primary_account) ||
+ if (identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
+ primary_account) ||
synced_data_deletion_in_progress_count_ == 0) {
// Invalidate the primary token, but do not revoke it.
- token_service_->UpdateCredentials(
- primary_account, OAuth2TokenServiceDelegate::kInvalidRefreshToken,
+ auto* accounts_mutator = identity_manager_->GetAccountsMutator();
+ accounts_mutator->InvalidateRefreshTokenForPrimaryAccount(
signin_metrics::SourceForRefreshTokenOperation::
kAccountReconcilor_GaiaCookiesDeletedByUser);
}
@@ -609,25 +631,30 @@ void AccountReconcilor::OnGaiaCookieDeletedByUserAction() {
std::vector<std::string> AccountReconcilor::LoadValidAccountsFromTokenService()
const {
- std::vector<std::string> chrome_accounts = token_service_->GetAccounts();
+ auto chrome_accounts_with_refresh_tokens =
+ identity_manager_->GetAccountsWithRefreshTokens();
+
+ std::vector<std::string> chrome_account_ids;
// Remove any accounts that have an error. There is no point in trying to
// reconcile them, since it won't work anyway. If the list ends up being
// empty then don't reconcile any accounts.
- for (auto i = chrome_accounts.begin(); i != chrome_accounts.end(); ++i) {
- if (token_service_->RefreshTokenHasError(*i)) {
- VLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: " << *i
+ for (const auto& chrome_account_with_refresh_tokens :
+ chrome_accounts_with_refresh_tokens) {
+ if (identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
+ chrome_account_with_refresh_tokens.account_id)) {
+ VLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: "
+ << chrome_account_with_refresh_tokens.account_id
<< " has error, don't reconcile";
- i->clear();
+ continue;
}
+ chrome_account_ids.push_back(chrome_account_with_refresh_tokens.account_id);
}
- base::Erase(chrome_accounts, std::string());
-
VLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: "
- << "Chrome " << chrome_accounts.size() << " accounts";
+ << "Chrome " << chrome_account_ids.size() << " accounts";
- return chrome_accounts;
+ return chrome_account_ids;
}
void AccountReconcilor::OnReceivedManageAccountsResponse(
@@ -676,8 +703,9 @@ void AccountReconcilor::FinishReconcile(
if (first_account.empty()) {
DCHECK(!delegate_->ShouldAbortReconcileIfPrimaryHasError());
reconcile_is_noop_ = !RevokeAllSecondaryTokens(
- token_service_, AccountReconcilorDelegate::RevokeTokenOption::kRevoke,
- primary_account, delegate_->IsAccountConsistencyEnforced(),
+ identity_manager_,
+ AccountReconcilorDelegate::RevokeTokenOption::kRevoke, primary_account,
+ delegate_->IsAccountConsistencyEnforced(),
signin_metrics::SourceForRefreshTokenOperation::
kAccountReconcilor_Reconcile);
} else {
@@ -796,16 +824,16 @@ bool AccountReconcilor::MarkAccountAsAddedToCookie(
return false;
}
-bool AccountReconcilor::IsTokenServiceReady() {
+bool AccountReconcilor::IsIdentityManagerReady() {
#if defined(OS_CHROMEOS)
// TODO(droger): ChromeOS should use the same logic as other platforms. See
// https://crbug.com/749535
- // On ChromeOS, there are cases where the token service is never fully
+ // On ChromeOS, there are cases where the IdentityManager is never fully
// initialized and AreAllCredentialsLoaded() always return false.
- return token_service_->AreAllCredentialsLoaded() ||
- (token_service_->GetAccounts().size() > 0);
+ return identity_manager_->AreRefreshTokensLoaded() ||
+ (identity_manager_->GetAccountsWithRefreshTokens().size() > 0);
#else
- return token_service_->AreAllCredentialsLoaded();
+ return identity_manager_->AreRefreshTokensLoaded();
#endif
}
@@ -819,6 +847,8 @@ void AccountReconcilor::OnSetAccountsInCookieCompleted(
error_during_last_reconcile_ = error;
delegate_->OnReconcileError(error_during_last_reconcile_);
}
+
+ set_accounts_in_progress_ = false;
is_reconcile_started_ = false;
timer_->Stop();
diff --git a/chromium/components/signin/core/browser/account_reconcilor.h b/chromium/components/signin/core/browser/account_reconcilor.h
index c13ed7f9786..6cf7cbd91ce 100644
--- a/chromium/components/signin/core/browser/account_reconcilor.h
+++ b/chromium/components/signin/core/browser/account_reconcilor.h
@@ -28,26 +28,21 @@
#include "components/signin/core/browser/signin_header_helper.h"
#include "components/signin/core/browser/signin_metrics.h"
#include "google_apis/gaia/google_service_auth_error.h"
-#include "google_apis/gaia/oauth2_token_service.h"
+#include "services/identity/public/cpp/identity_manager.h"
// Enables usage of Gaia Auth Multilogin endpoint for identity consistency.
extern const base::Feature kUseMultiloginEndpoint;
-namespace identity {
-class IdentityManager;
-}
-
namespace signin {
class AccountReconcilorDelegate;
}
-class ProfileOAuth2TokenService;
class SigninClient;
class AccountReconcilor : public KeyedService,
public content_settings::Observer,
public GaiaCookieManagerService::Observer,
- public OAuth2TokenService::Observer {
+ public identity::IdentityManager::Observer {
public:
// When an instance of this class exists, the account reconcilor is suspended.
// It will automatically restart when all instances of Lock have been
@@ -58,7 +53,7 @@ class AccountReconcilor : public KeyedService,
~Lock();
private:
- AccountReconcilor* reconcilor_;
+ base::WeakPtr<AccountReconcilor> reconcilor_;
THREAD_CHECKER(thread_checker_);
DISALLOW_COPY_AND_ASSIGN(Lock);
};
@@ -99,7 +94,6 @@ class AccountReconcilor : public KeyedService,
};
AccountReconcilor(
- ProfileOAuth2TokenService* token_service,
identity::IdentityManager* identity_manager,
SigninClient* client,
GaiaCookieManagerService* cookie_manager_service,
@@ -196,6 +190,8 @@ class AccountReconcilor : public KeyedService,
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
GetAccountsFromCookieFailure);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+ ExtraCookieChangeNotification);
+ FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
StartReconcileNoop);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
StartReconcileNoopWithDots);
@@ -233,13 +229,13 @@ class AccountReconcilor : public KeyedService,
void set_timer_for_testing(std::unique_ptr<base::OneShotTimer> timer);
- bool IsRegisteredWithTokenService() const {
- return registered_with_token_service_;
+ bool IsRegisteredWithIdentityManager() const {
+ return registered_with_identity_manager_;
}
// Register and unregister with dependent services.
- void RegisterWithTokenService();
- void UnregisterWithTokenService();
+ void RegisterWithIdentityManager();
+ void UnregisterWithIdentityManager();
void RegisterWithCookieManagerService();
void UnregisterWithCookieManagerService();
void RegisterWithContentSettings();
@@ -269,15 +265,15 @@ class AccountReconcilor : public KeyedService,
bool MarkAccountAsAddedToCookie(const std::string& account_id);
// The reconcilor only starts when the token service is ready.
- bool IsTokenServiceReady();
+ bool IsIdentityManagerReady();
- // Overriden from content_settings::Observer.
+ // Overridden from content_settings::Observer.
void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const std::string& resource_identifier) override;
- // Overriden from GaiaGookieManagerService::Observer.
+ // Overridden from GaiaGookieManagerService::Observer.
void OnAddAccountToCookieCompleted(
const std::string& account_id,
const GoogleServiceAuthError& error) override;
@@ -289,11 +285,12 @@ class AccountReconcilor : public KeyedService,
const GoogleServiceAuthError& error) override;
void OnGaiaCookieDeletedByUserAction() override;
- // Overriden from OAuth2TokenService::Observer.
- void OnEndBatchChanges() override;
+ // Overridden from identity::IdentityManager::Observer.
+ void OnEndBatchOfRefreshTokenStateChanges() override;
void OnRefreshTokensLoaded() override;
- void OnAuthErrorChanged(const std::string& account_id,
- const GoogleServiceAuthError& error) override;
+ void OnErrorStateOfRefreshTokenUpdatedForAccount(
+ const AccountInfo& account_info,
+ const GoogleServiceAuthError& error) override;
void FinishReconcileWithMultiloginEndpoint(
const std::string& primary_account,
@@ -314,9 +311,6 @@ class AccountReconcilor : public KeyedService,
std::unique_ptr<signin::AccountReconcilorDelegate> delegate_;
- // The ProfileOAuth2TokenService associated with this reconcilor.
- ProfileOAuth2TokenService* token_service_;
-
// The IdentityManager associated with this reconcilor.
identity::IdentityManager* identity_manager_;
@@ -326,7 +320,7 @@ class AccountReconcilor : public KeyedService,
// The GaiaCookieManagerService associated with this reconcilor.
GaiaCookieManagerService* cookie_manager_service_;
- bool registered_with_token_service_;
+ bool registered_with_identity_manager_;
bool registered_with_cookie_manager_service_;
bool registered_with_content_settings_;
@@ -353,8 +347,8 @@ class AccountReconcilor : public KeyedService,
bool reconcile_is_noop_;
// Used during reconcile action.
- // These members are used to validate the tokens in OAuth2TokenService.
- std::vector<std::string> add_to_cookie_;
+ std::vector<std::string> add_to_cookie_; // Progress of AddAccount calls.
+ bool set_accounts_in_progress_; // Progress of SetAccounts calls.
bool chrome_accounts_changed_;
// Used for the Lock.
diff --git a/chromium/components/signin/core/browser/account_reconcilor_unittest.cc b/chromium/components/signin/core/browser/account_reconcilor_unittest.cc
index b4128da739d..0ac578b3a55 100644
--- a/chromium/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -10,12 +10,12 @@
#include <utility>
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/scoped_observer.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
#include "base/time/time.h"
#include "base/timer/mock_timer.h"
#include "build/build_config.h"
@@ -40,6 +40,8 @@
#include "google_apis/gaia/google_service_auth_error.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "services/identity/public/cpp/identity_test_environment.h"
+#include "services/identity/public/cpp/identity_test_utils.h"
+#include "services/identity/public/cpp/primary_account_mutator.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -118,13 +120,11 @@ class SpyReconcilorDelegate : public signin::AccountReconcilorDelegate {
class DummyAccountReconcilorWithDelegate : public AccountReconcilor {
public:
DummyAccountReconcilorWithDelegate(
- ProfileOAuth2TokenService* token_service,
identity::IdentityManager* identity_manager,
SigninClient* client,
GaiaCookieManagerService* cookie_manager_service,
signin::AccountConsistencyMethod account_consistency)
: AccountReconcilor(
- token_service,
identity_manager,
client,
cookie_manager_service,
@@ -140,13 +140,11 @@ class DummyAccountReconcilorWithDelegate : public AccountReconcilor {
// Takes ownership of |delegate|.
// gmock can't work with move only parameters.
DummyAccountReconcilorWithDelegate(
- ProfileOAuth2TokenService* token_service,
identity::IdentityManager* identity_manager,
SigninClient* client,
GaiaCookieManagerService* cookie_manager_service,
signin::AccountReconcilorDelegate* delegate)
: AccountReconcilor(
- token_service,
identity_manager,
client,
cookie_manager_service,
@@ -167,7 +165,6 @@ class DummyAccountReconcilorWithDelegate : public AccountReconcilor {
return std::make_unique<signin::MirrorAccountReconcilorDelegate>(
identity_manager);
case signin::AccountConsistencyMethod::kDisabled:
- case signin::AccountConsistencyMethod::kDiceFixAuthErrors:
return std::make_unique<signin::AccountReconcilorDelegate>();
case signin::AccountConsistencyMethod::kDiceMigration:
case signin::AccountConsistencyMethod::kDice:
@@ -188,14 +185,12 @@ class MockAccountReconcilor
: public testing::StrictMock<DummyAccountReconcilorWithDelegate> {
public:
explicit MockAccountReconcilor(
- ProfileOAuth2TokenService* token_service,
identity::IdentityManager* identity_manager,
SigninClient* client,
GaiaCookieManagerService* cookie_manager_service,
signin::AccountConsistencyMethod account_consistency);
explicit MockAccountReconcilor(
- ProfileOAuth2TokenService* token_service,
identity::IdentityManager* identity_manager,
SigninClient* client,
GaiaCookieManagerService* cookie_manager_service,
@@ -208,26 +203,22 @@ class MockAccountReconcilor
};
MockAccountReconcilor::MockAccountReconcilor(
- ProfileOAuth2TokenService* token_service,
identity::IdentityManager* identity_manager,
SigninClient* client,
GaiaCookieManagerService* cookie_manager_service,
signin::AccountConsistencyMethod account_consistency)
: testing::StrictMock<DummyAccountReconcilorWithDelegate>(
- token_service,
identity_manager,
client,
cookie_manager_service,
account_consistency) {}
MockAccountReconcilor::MockAccountReconcilor(
- ProfileOAuth2TokenService* token_service,
identity::IdentityManager* identity_manager,
SigninClient* client,
GaiaCookieManagerService* cookie_manager_service,
std::unique_ptr<signin::AccountReconcilorDelegate> delegate)
: testing::StrictMock<DummyAccountReconcilorWithDelegate>(
- token_service,
identity_manager,
client,
cookie_manager_service,
@@ -242,6 +233,21 @@ struct Cookie {
}
};
+// Converts CookieParams to ListedAccounts.
+gaia::ListedAccount ListedAccounfFromCookieParams(
+ const signin::CookieParams& params,
+ const std::string& account_id) {
+ gaia::ListedAccount listed_account;
+ listed_account.id = account_id;
+ listed_account.email = params.email;
+ listed_account.gaia_id = params.gaia_id;
+ listed_account.raw_email = params.email;
+ listed_account.valid = params.valid;
+ listed_account.signed_out = params.signed_out;
+ listed_account.verified = params.verified;
+ return listed_account;
+}
+
} // namespace
class AccountReconcilorTest : public ::testing::Test {
@@ -249,8 +255,9 @@ class AccountReconcilorTest : public ::testing::Test {
AccountReconcilorTest();
~AccountReconcilorTest() override;
- FakeSigninManagerForTesting* signin_manager() { return &signin_manager_; }
- FakeProfileOAuth2TokenService* token_service() { return &token_service_; }
+ identity::IdentityTestEnvironment* identity_test_env() {
+ return &identity_test_env_;
+ }
DiceTestSigninClient* test_signin_client() { return &test_signin_client_; }
AccountTrackerService* account_tracker() { return &account_tracker_; }
FakeGaiaCookieManagerService* cookie_manager_service() {
@@ -262,8 +269,7 @@ class AccountReconcilorTest : public ::testing::Test {
MockAccountReconcilor* GetMockReconcilor(
std::unique_ptr<signin::AccountReconcilorDelegate> delegate);
- std::string ConnectProfileToAccount(const std::string& gaia_id,
- const std::string& username);
+ AccountInfo ConnectProfileToAccount(const std::string& email);
std::string PickAccountIdForAccount(const std::string& gaia_id,
const std::string& username);
@@ -290,12 +296,13 @@ class AccountReconcilorTest : public ::testing::Test {
void DeleteReconcilor() { mock_reconcilor_.reset(); }
private:
- base::MessageLoop loop;
+ base::test::ScopedTaskEnvironment task_environment_;
signin::AccountConsistencyMethod account_consistency_;
sync_preferences::TestingPrefServiceSyncable pref_service_;
DiceTestSigninClient test_signin_client_;
FakeProfileOAuth2TokenService token_service_;
AccountTrackerService account_tracker_;
+ network::TestURLLoaderFactory test_url_loader_factory_;
FakeGaiaCookieManagerService cookie_manager_service_;
FakeSigninManagerForTesting signin_manager_;
identity::IdentityTestEnvironment identity_test_env_;
@@ -347,9 +354,10 @@ AccountReconcilorTest::AccountReconcilorTest()
test_signin_client_(&pref_service_),
token_service_(&pref_service_),
cookie_manager_service_(&token_service_,
- &test_signin_client_),
+ &test_signin_client_,
+ &test_url_loader_factory_),
#if defined(OS_CHROMEOS)
- signin_manager_(&test_signin_client_, &account_tracker_),
+ signin_manager_(&test_signin_client_, &token_service_, &account_tracker_),
#else
signin_manager_(&test_signin_client_,
&token_service_,
@@ -379,8 +387,8 @@ AccountReconcilorTest::AccountReconcilorTest()
MockAccountReconcilor* AccountReconcilorTest::GetMockReconcilor() {
if (!mock_reconcilor_) {
mock_reconcilor_ = std::make_unique<MockAccountReconcilor>(
- &token_service_, identity_test_env_.identity_manager(),
- &test_signin_client_, &cookie_manager_service_, account_consistency_);
+ identity_test_env_.identity_manager(), &test_signin_client_,
+ &cookie_manager_service_, account_consistency_);
}
return mock_reconcilor_.get();
@@ -389,8 +397,8 @@ MockAccountReconcilor* AccountReconcilorTest::GetMockReconcilor() {
MockAccountReconcilor* AccountReconcilorTest::GetMockReconcilor(
std::unique_ptr<signin::AccountReconcilorDelegate> delegate) {
mock_reconcilor_ = std::make_unique<MockAccountReconcilor>(
- &token_service_, identity_test_env_.identity_manager(),
- &test_signin_client_, &cookie_manager_service_, std::move(delegate));
+ identity_test_env_.identity_manager(), &test_signin_client_,
+ &cookie_manager_service_, std::move(delegate));
return mock_reconcilor_.get();
}
@@ -405,16 +413,11 @@ AccountReconcilorTest::~AccountReconcilorTest() {
token_service_.Shutdown();
}
-std::string AccountReconcilorTest::ConnectProfileToAccount(
- const std::string& gaia_id,
- const std::string& username) {
- const std::string account_id = SeedAccountInfo(gaia_id, username);
-#if !defined(OS_CHROMEOS)
- signin_manager()->set_password("password");
-#endif
- signin_manager()->SetAuthenticatedAccountInfo(gaia_id, username);
- token_service()->UpdateCredentials(account_id, "refresh_token");
- return account_id;
+AccountInfo AccountReconcilorTest::ConnectProfileToAccount(
+ const std::string& email) {
+ AccountInfo account_info =
+ identity_test_env()->MakePrimaryAccountAvailable(email);
+ return account_info;
}
std::string AccountReconcilorTest::PickAccountIdForAccount(
@@ -522,9 +525,12 @@ class AccountReconcilorTestTable
};
AccountReconcilorTestTable() {
- accounts_['A'] = {"a@gmail.com", "A"};
- accounts_['B'] = {"b@gmail.com", "B"};
- accounts_['C'] = {"c@gmail.com", "C"};
+ accounts_['A'] = {"a@gmail.com",
+ identity::GetTestGaiaIdForEmail("a@gmail.com")};
+ accounts_['B'] = {"b@gmail.com",
+ identity::GetTestGaiaIdForEmail("b@gmail.com")};
+ accounts_['C'] = {"c@gmail.com",
+ identity::GetTestGaiaIdForEmail("c@gmail.com")};
}
// Build Tokens from string.
@@ -569,21 +575,26 @@ class AccountReconcilorTestTable
// Checks that the tokens in the TokenService match the tokens.
void VerifyCurrentTokens(const std::vector<Token>& tokens) {
- EXPECT_EQ(token_service()->GetAccounts().size(), tokens.size());
+ auto* identity_manager = identity_test_env()->identity_manager();
+ EXPECT_EQ(identity_manager->GetAccountsWithRefreshTokens().size(),
+ tokens.size());
+
bool authenticated_account_found = false;
for (const Token& token : tokens) {
std::string account_id =
PickAccountIdForAccount(token.gaia_id, token.email);
- EXPECT_TRUE(token_service()->RefreshTokenIsAvailable(account_id));
- EXPECT_EQ(token.has_error,
- token_service()->RefreshTokenHasError(account_id));
+ EXPECT_TRUE(identity_manager->HasAccountWithRefreshToken(account_id));
+ EXPECT_EQ(
+ token.has_error,
+ identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
+ account_id));
if (token.is_authenticated) {
- EXPECT_EQ(account_id, signin_manager()->GetAuthenticatedAccountId());
+ EXPECT_EQ(account_id, identity_manager->GetPrimaryAccountId());
authenticated_account_found = true;
}
}
if (!authenticated_account_found)
- EXPECT_EQ("", signin_manager()->GetAuthenticatedAccountId());
+ EXPECT_EQ("", identity_manager->GetPrimaryAccountId());
}
// Checks that reconcile is idempotent.
@@ -620,10 +631,22 @@ class AccountReconcilorTestTable
}
void ConfigureCookieManagerService(const std::vector<Cookie>& cookies) {
- std::vector<FakeGaiaCookieManagerService::CookieParams> cookie_params;
+ std::vector<signin::CookieParams> cookie_params;
for (const auto& cookie : cookies) {
std::string gaia_id = cookie.gaia_id;
- cookie_params.push_back({accounts_[gaia_id[0]].email, gaia_id,
+
+ // Figure the account token of this specific account id,
+ // ie 'A', 'B', or 'C'.
+ char account_key = '\0';
+ for (const auto& account : accounts_) {
+ if (account.second.gaia_id == gaia_id) {
+ account_key = account.first;
+ break;
+ }
+ }
+ ASSERT_NE(account_key, '\0');
+
+ cookie_params.push_back({accounts_[account_key].email, gaia_id,
cookie.is_valid, false /* signed_out */,
true /* verified */});
}
@@ -631,6 +654,10 @@ class AccountReconcilorTestTable
cookie_manager_service()->set_list_accounts_stale_for_testing(true);
}
+ std::string GaiaIdForAccountKey(char account_key) {
+ return accounts_[account_key].gaia_id;
+ }
+
std::map<char, Account> accounts_;
};
@@ -643,17 +670,15 @@ class AccountReconcilorTestTable
TEST_P(AccountReconcilorMirrorEndpointParamTest, SigninManagerRegistration) {
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
- ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService());
+ ASSERT_FALSE(reconcilor->IsRegisteredWithIdentityManager());
- account_tracker()->SeedAccountInfo("12345", "user@gmail.com");
- signin_manager()->SignIn("12345", "user@gmail.com", "password");
- ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
+ identity_test_env()->MakePrimaryAccountAvailable("user@gmail.com");
+ ASSERT_TRUE(reconcilor->IsRegisteredWithIdentityManager());
EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
- signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST,
- signin_metrics::SignoutDelete::IGNORE_METRIC);
- ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService());
+ identity_test_env()->ClearPrimaryAccount();
+ ASSERT_FALSE(reconcilor->IsRegisteredWithIdentityManager());
}
// This method requires the use of the |TestSigninClient| to be created from the
@@ -662,25 +687,29 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, SigninManagerRegistration) {
// causes the try_bots to time out.
TEST_P(AccountReconcilorMirrorEndpointParamTest, Reauth) {
const std::string email = "user@gmail.com";
- const std::string account_id = ConnectProfileToAccount("12345", email);
+ AccountInfo account_info = ConnectProfileToAccount(email);
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
- ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
+ ASSERT_TRUE(reconcilor->IsRegisteredWithIdentityManager());
// Simulate reauth. The state of the reconcilor should not change.
- signin_manager()->OnExternalSigninCompleted(email);
- ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
+ auto* account_mutator =
+ identity_test_env()->identity_manager()->GetPrimaryAccountMutator();
+ DCHECK(account_mutator);
+ account_mutator->SetPrimaryAccount(account_info.account_id);
+
+ ASSERT_TRUE(reconcilor->IsRegisteredWithIdentityManager());
}
#endif // !defined(OS_CHROMEOS)
TEST_P(AccountReconcilorMirrorEndpointParamTest, ProfileAlreadyConnected) {
- ConnectProfileToAccount("12345", "user@gmail.com");
+ ConnectProfileToAccount("user@gmail.com");
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
- ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
+ ASSERT_TRUE(reconcilor->IsRegisteredWithIdentityManager());
}
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
@@ -901,15 +930,18 @@ TEST_P(AccountReconcilorTestTable, TableRowTest) {
std::vector<Token> tokens_before_reconcile =
ParseTokenString(GetParam().tokens);
for (const Token& token : tokens_before_reconcile) {
- std::string account_id = SeedAccountInfo(token.gaia_id, token.email);
- if (token.is_authenticated)
- ConnectProfileToAccount(token.gaia_id, token.email);
- else
- token_service()->UpdateCredentials(account_id, "refresh_token");
+ std::string account_id;
+ if (token.is_authenticated) {
+ account_id = ConnectProfileToAccount(token.email).account_id;
+ } else {
+ account_id = SeedAccountInfo(token.gaia_id, token.email);
+ identity_test_env()->SetRefreshTokenForAccount(account_id);
+ }
if (token.has_error) {
- token_service()->UpdateAuthErrorForTesting(
- account_id, GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ identity::UpdatePersistentErrorOfRefreshTokenForAccount(
+ identity_test_env()->identity_manager(), account_id,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
}
}
VerifyCurrentTokens(tokens_before_reconcile);
@@ -934,12 +966,14 @@ TEST_P(AccountReconcilorTestTable, TableRowTest) {
continue;
}
std::string cookie(1, GetParam().gaia_api_calls[i]);
- EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(cookie)).Times(1);
+ std::string account_id_for_cookie = GaiaIdForAccountKey(cookie[0]);
+ EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id_for_cookie))
+ .Times(1);
// MergeSession fixes an existing cookie or appends it at the end.
auto it = std::find(cookies.begin(), cookies.end(),
- Cookie{cookie, false /* is_valid */});
+ Cookie{account_id_for_cookie, false /* is_valid */});
if (it == cookies.end())
- cookies.push_back({cookie, true});
+ cookies.push_back({account_id_for_cookie, true});
else
it->is_valid = true;
}
@@ -1015,17 +1049,18 @@ TEST_P(AccountReconcilorTestDiceMultilogin, TableRowTest) {
ParseTokenString(GetParam().tokens);
Token primary_account;
for (const Token& token : tokens_before_reconcile) {
- std::string account_id = SeedAccountInfo(token.gaia_id, token.email);
+ std::string account_id;
if (token.is_authenticated) {
- primary_account = token;
- ConnectProfileToAccount(token.gaia_id, token.email);
+ account_id = ConnectProfileToAccount(token.email).account_id;
} else {
- token_service()->UpdateCredentials(account_id, "refresh_token");
+ account_id = SeedAccountInfo(token.gaia_id, token.email);
+ identity_test_env()->SetRefreshTokenForAccount(account_id);
}
if (token.has_error) {
- token_service()->UpdateAuthErrorForTesting(
- account_id, GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ identity::UpdatePersistentErrorOfRefreshTokenForAccount(
+ identity_test_env()->identity_manager(), account_id,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
}
}
VerifyCurrentTokens(tokens_before_reconcile);
@@ -1114,11 +1149,10 @@ class AccountReconcilorDiceEndpointParamTest
TEST_P(AccountReconcilorDiceEndpointParamTest, DiceTokenServiceRegistration) {
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
- ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
+ ASSERT_TRUE(reconcilor->IsRegisteredWithIdentityManager());
- account_tracker()->SeedAccountInfo("12345", "user@gmail.com");
- signin_manager()->SignIn("12345", "user@gmail.com", "password");
- ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
+ identity_test_env()->MakePrimaryAccountAvailable("user@gmail.com");
+ ASSERT_TRUE(reconcilor->IsRegisteredWithIdentityManager());
// Reconcilor should not logout all accounts from the cookies when
// SigninManager signs out.
@@ -1126,16 +1160,15 @@ TEST_P(AccountReconcilorDiceEndpointParamTest, DiceTokenServiceRegistration) {
EXPECT_CALL(*GetMockReconcilor(), PerformSetCookiesAction(::testing::_))
.Times(0);
- signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST,
- signin_metrics::SignoutDelete::IGNORE_METRIC);
- ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
+ identity_test_env()->ClearPrimaryAccount();
+ ASSERT_TRUE(reconcilor->IsRegisteredWithIdentityManager());
}
// Tests that reconcile starts even when Sync is not enabled.
TEST_P(AccountReconcilorDiceEndpointParamTest, DiceReconcileWithoutSignin) {
// Add a token in Chrome but do not sign in.
- const std::string account_id = SeedAccountInfo("12345", "user@gmail.com");
- token_service()->UpdateCredentials(account_id, "refresh_token");
+ const std::string account_id =
+ identity_test_env()->MakeAccountAvailable("user@gmail.com").account_id;
cookie_manager_service()->SetListAccountsResponseNoAccounts();
if (!IsMultiloginEnabled()) {
@@ -1186,19 +1219,24 @@ TEST_P(AccountReconcilorDiceEndpointParamTest, DiceReconcileNoop) {
TEST_P(AccountReconcilorDiceEndpointParamTest,
DiceReconcileReuseGaiaFirstAccount) {
// Add accounts 1 and 2 to the token service.
- const std::string account_id_1 = SeedAccountInfo("12345", "user@gmail.com");
- const std::string account_id_2 = SeedAccountInfo("67890", "other@gmail.com");
- token_service()->UpdateCredentials(account_id_1, "refresh_token");
- token_service()->UpdateCredentials(account_id_2, "refresh_token");
-
- ASSERT_EQ(2u, token_service()->GetAccounts().size());
- ASSERT_EQ(account_id_1, token_service()->GetAccounts()[0]);
- ASSERT_EQ(account_id_2, token_service()->GetAccounts()[1]);
+ const AccountInfo account_info_1 =
+ identity_test_env()->MakeAccountAvailable("user@gmail.com");
+ const std::string account_id_1 = account_info_1.account_id;
+ const AccountInfo account_info_2 =
+ identity_test_env()->MakeAccountAvailable("other@gmail.com");
+ const std::string account_id_2 = account_info_2.account_id;
+
+ auto* identity_manager = identity_test_env()->identity_manager();
+ std::vector<AccountInfo> accounts =
+ identity_manager->GetAccountsWithRefreshTokens();
+ ASSERT_EQ(2u, accounts.size());
+ ASSERT_TRUE(identity_manager->HasAccountWithRefreshToken(account_id_1));
+ ASSERT_TRUE(identity_manager->HasAccountWithRefreshToken(account_id_2));
// Add accounts 2 and 3 to the Gaia cookie.
const std::string account_id_3 = SeedAccountInfo("9999", "foo@gmail.com");
cookie_manager_service()->SetListAccountsResponseTwoAccounts(
- "other@gmail.com", "67890", "foo@gmail.com", "9999");
+ account_info_2.email, account_info_2.gaia, "foo@gmail.com", "9999");
if (!IsMultiloginEnabled()) {
testing::InSequence mock_sequence;
@@ -1207,7 +1245,7 @@ TEST_P(AccountReconcilorDiceEndpointParamTest,
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id_2));
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id_1));
} else {
- std::vector<std::string> accounts_to_send = {account_id_1, account_id_2};
+ std::vector<std::string> accounts_to_send = {account_id_2, account_id_1};
// Send accounts to Gaia in any order, it will determine the order itself in
// PRESERVE order.
const signin::MultiloginParameters params(
@@ -1237,16 +1275,22 @@ TEST_P(AccountReconcilorDiceEndpointParamTest,
// lost.
TEST_P(AccountReconcilorDiceEndpointParamTest, DiceLastKnownFirstAccount) {
// Add accounts to the token service and the Gaia cookie in a different order.
- const std::string account_id_1 = SeedAccountInfo("12345", "user@gmail.com");
- const std::string account_id_2 = SeedAccountInfo("67890", "other@gmail.com");
+ AccountInfo account_info_1 =
+ identity_test_env()->MakeAccountAvailable("user@gmail.com");
+ const std::string account_id_1 = account_info_1.account_id;
+ AccountInfo account_info_2 =
+ identity_test_env()->MakeAccountAvailable("other@gmail.com");
+ const std::string account_id_2 = account_info_2.account_id;
cookie_manager_service()->SetListAccountsResponseTwoAccounts(
- "other@gmail.com", "67890", "user@gmail.com", "12345");
- token_service()->UpdateCredentials(account_id_1, "refresh_token");
- token_service()->UpdateCredentials(account_id_2, "refresh_token");
+ account_info_2.email, account_info_2.gaia, account_info_1.email,
+ account_info_1.gaia);
- ASSERT_EQ(2u, token_service()->GetAccounts().size());
- ASSERT_EQ(account_id_1, token_service()->GetAccounts()[0]);
- ASSERT_EQ(account_id_2, token_service()->GetAccounts()[1]);
+ auto* identity_manager = identity_test_env()->identity_manager();
+ std::vector<AccountInfo> accounts =
+ identity_manager->GetAccountsWithRefreshTokens();
+ ASSERT_EQ(2u, accounts.size());
+ ASSERT_TRUE(identity_manager->HasAccountWithRefreshToken(account_id_1));
+ ASSERT_TRUE(identity_manager->HasAccountWithRefreshToken(account_id_2));
// Do one reconcile. It should do nothing but to populating the last known
// account.
@@ -1337,8 +1381,7 @@ TEST_P(AccountReconcilorDiceEndpointParamTest, UnverifiedAccountMerge) {
// Add a token to Chrome.
const std::string chrome_account_id =
- SeedAccountInfo("67890", "other@gmail.com");
- token_service()->UpdateCredentials(chrome_account_id, "refresh_token");
+ identity_test_env()->MakeAccountAvailable("other@gmail.com").account_id;
if (!IsMultiloginEnabled()) {
// Check that the Chrome account is merged and the unverified account is not
@@ -1379,10 +1422,10 @@ TEST_P(AccountReconcilorDiceEndpointParamTest, DiceMigrationAfterNoop) {
pref_service()->SetBoolean(prefs::kTokenServiceDiceCompatible, true);
// Chrome account is consistent with the cookie.
- const std::string account_id = SeedAccountInfo("12345", "user@gmail.com");
- token_service()->UpdateCredentials(account_id, "refresh_token");
- cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
- "12345");
+ AccountInfo account_info =
+ identity_test_env()->MakeAccountAvailable("user@gmail.com");
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ account_info.email, account_info.gaia);
AccountReconcilor* reconcilor = GetMockReconcilor();
// Dice is not enabled by default.
EXPECT_FALSE(reconcilor->delegate_->IsAccountConsistencyEnforced());
@@ -1409,10 +1452,10 @@ TEST_P(AccountReconcilorDiceEndpointParamTest,
SetAccountConsistency(signin::AccountConsistencyMethod::kDiceMigration);
// Chrome account is consistent with the cookie.
- const std::string account_id = SeedAccountInfo("12345", "user@gmail.com");
- token_service()->UpdateCredentials(account_id, "refresh_token");
- cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
- "12345");
+ AccountInfo account_info =
+ identity_test_env()->MakeAccountAvailable("user@gmail.com");
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ account_info.email, account_info.gaia);
AccountReconcilor* reconcilor = GetMockReconcilor();
// Dice is not enabled by default.
EXPECT_FALSE(reconcilor->delegate_->IsAccountConsistencyEnforced());
@@ -1440,7 +1483,7 @@ TEST_P(AccountReconcilorDiceEndpointParamTest, DiceNoMigrationAfterReconcile) {
// Add a token in Chrome.
const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
+ ConnectProfileToAccount("user@gmail.com").account_id;
cookie_manager_service()->SetListAccountsResponseNoAccounts();
AccountReconcilor* reconcilor = GetMockReconcilor();
@@ -1480,12 +1523,14 @@ TEST_P(AccountReconcilorDiceEndpointParamTest, MigrationClearSecondaryTokens) {
// Add a tokens in Chrome, signin to Sync, but no Gaia cookies.
const std::string account_id_1 =
- ConnectProfileToAccount("12345", "user@gmail.com");
- const std::string account_id_2 = SeedAccountInfo("67890", "other@gmail.com");
- token_service()->UpdateCredentials(account_id_2, "refresh_token");
+ ConnectProfileToAccount("user@gmail.com").account_id;
+ const std::string account_id_2 =
+ identity_test_env()->MakeAccountAvailable("other@gmail.com").account_id;
cookie_manager_service()->SetListAccountsResponseNoAccounts();
- ASSERT_TRUE(token_service()->RefreshTokenIsAvailable(account_id_1));
- ASSERT_TRUE(token_service()->RefreshTokenIsAvailable(account_id_2));
+
+ auto* identity_manager = identity_test_env()->identity_manager();
+ ASSERT_TRUE(identity_manager->HasAccountWithRefreshToken(account_id_1));
+ ASSERT_TRUE(identity_manager->HasAccountWithRefreshToken(account_id_2));
// Reconcile should revoke the secondary account.
AccountReconcilor* reconcilor = GetMockReconcilor();
@@ -1512,8 +1557,8 @@ TEST_P(AccountReconcilorDiceEndpointParamTest, MigrationClearSecondaryTokens) {
ASSERT_FALSE(reconcilor->is_reconcile_started_);
ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_OK, reconcilor->GetState());
- EXPECT_TRUE(token_service()->RefreshTokenIsAvailable(account_id_1));
- EXPECT_FALSE(token_service()->RefreshTokenIsAvailable(account_id_2));
+ EXPECT_TRUE(identity_manager->HasAccountWithRefreshToken(account_id_1));
+ EXPECT_FALSE(identity_manager->HasAccountWithRefreshToken(account_id_2));
// Profile was not migrated.
EXPECT_FALSE(test_signin_client()->is_ready_for_dice_migration());
@@ -1527,13 +1572,15 @@ TEST_P(AccountReconcilorDiceEndpointParamTest, MigrationClearAllTokens) {
pref_service()->SetBoolean(prefs::kTokenServiceDiceCompatible, true);
// Add a tokens in Chrome but no Gaia cookies.
- const std::string account_id_1 = SeedAccountInfo("12345", "user@gmail.com");
- const std::string account_id_2 = SeedAccountInfo("67890", "other@gmail.com");
- token_service()->UpdateCredentials(account_id_1, "refresh_token");
- token_service()->UpdateCredentials(account_id_2, "refresh_token");
+ const std::string account_id_1 =
+ identity_test_env()->MakeAccountAvailable("user@gmail.com").account_id;
+ const std::string account_id_2 =
+ identity_test_env()->MakeAccountAvailable("other@gmail.com").account_id;
cookie_manager_service()->SetListAccountsResponseNoAccounts();
- ASSERT_TRUE(token_service()->RefreshTokenIsAvailable(account_id_1));
- ASSERT_TRUE(token_service()->RefreshTokenIsAvailable(account_id_2));
+
+ auto* identity_manager = identity_test_env()->identity_manager();
+ ASSERT_TRUE(identity_manager->HasAccountWithRefreshToken(account_id_1));
+ ASSERT_TRUE(identity_manager->HasAccountWithRefreshToken(account_id_2));
// Reconcile should revoke the secondary account.
AccountReconcilor* reconcilor = GetMockReconcilor();
@@ -1543,8 +1590,8 @@ TEST_P(AccountReconcilorDiceEndpointParamTest, MigrationClearAllTokens) {
ASSERT_FALSE(reconcilor->is_reconcile_started_);
ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_OK, reconcilor->GetState());
- EXPECT_FALSE(token_service()->RefreshTokenIsAvailable(account_id_1));
- EXPECT_FALSE(token_service()->RefreshTokenIsAvailable(account_id_2));
+ EXPECT_FALSE(identity_manager->HasAccountWithRefreshToken(account_id_1));
+ EXPECT_FALSE(identity_manager->HasAccountWithRefreshToken(account_id_2));
// Profile is now ready for migration on next startup.
base::RunLoop().RunUntilIdle();
@@ -1559,17 +1606,22 @@ TEST_F(AccountReconcilorTest, DiceDeleteCookie) {
SetAccountConsistency(signin::AccountConsistencyMethod::kDice);
const std::string primary_account_id =
- account_tracker()->SeedAccountInfo("12345", "user@gmail.com");
- token_service()->UpdateCredentials(primary_account_id, "refresh_token");
- signin_manager()->SignIn("12345", "user@gmail.com", "password");
+ identity_test_env()
+ ->MakePrimaryAccountAvailable("user@gmail.com")
+ .account_id;
const std::string secondary_account_id =
- SeedAccountInfo("67890", "other@gmail.com");
- token_service()->UpdateCredentials(secondary_account_id, "refresh_token");
+ identity_test_env()->MakeAccountAvailable("other@gmail.com").account_id;
- ASSERT_TRUE(token_service()->RefreshTokenIsAvailable(primary_account_id));
- ASSERT_FALSE(token_service()->RefreshTokenHasError(primary_account_id));
- ASSERT_TRUE(token_service()->RefreshTokenIsAvailable(secondary_account_id));
- ASSERT_FALSE(token_service()->RefreshTokenHasError(secondary_account_id));
+ auto* identity_manager = identity_test_env()->identity_manager();
+ ASSERT_TRUE(identity_manager->HasAccountWithRefreshToken(primary_account_id));
+ ASSERT_FALSE(
+ identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
+ primary_account_id));
+ ASSERT_TRUE(
+ identity_manager->HasAccountWithRefreshToken(secondary_account_id));
+ ASSERT_FALSE(
+ identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
+ secondary_account_id));
AccountReconcilor* reconcilor = GetMockReconcilor();
@@ -1578,30 +1630,38 @@ TEST_F(AccountReconcilorTest, DiceDeleteCookie) {
std::unique_ptr<AccountReconcilor::ScopedSyncedDataDeletion> deletion =
reconcilor->GetScopedSyncDataDeletion();
reconcilor->OnGaiaCookieDeletedByUserAction();
- EXPECT_TRUE(token_service()->RefreshTokenIsAvailable(primary_account_id));
- EXPECT_FALSE(token_service()->RefreshTokenHasError(primary_account_id));
+ EXPECT_TRUE(
+ identity_manager->HasAccountWithRefreshToken(primary_account_id));
+ EXPECT_FALSE(
+ identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
+ primary_account_id));
EXPECT_FALSE(
- token_service()->RefreshTokenIsAvailable(secondary_account_id));
+ identity_manager->HasAccountWithRefreshToken(secondary_account_id));
}
- token_service()->UpdateCredentials(secondary_account_id, "refresh_token");
+ identity_test_env()->SetRefreshTokenForAccount(secondary_account_id);
reconcilor->OnGaiaCookieDeletedByUserAction();
// Without scoped deletion, the primary token is also invalidated.
- EXPECT_TRUE(token_service()->RefreshTokenIsAvailable(primary_account_id));
- EXPECT_TRUE(token_service()->RefreshTokenHasError(primary_account_id));
+ EXPECT_TRUE(identity_manager->HasAccountWithRefreshToken(primary_account_id));
+ EXPECT_TRUE(
+ identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
+ primary_account_id));
EXPECT_EQ(GoogleServiceAuthError::InvalidGaiaCredentialsReason::
CREDENTIALS_REJECTED_BY_CLIENT,
- token_service()
- ->GetAuthError(primary_account_id)
+ identity_manager
+ ->GetErrorStateOfRefreshTokenForAccount(primary_account_id)
.GetInvalidGaiaCredentialsReason());
- EXPECT_FALSE(token_service()->RefreshTokenIsAvailable(secondary_account_id));
+ EXPECT_FALSE(
+ identity_manager->HasAccountWithRefreshToken(secondary_account_id));
// If the primary account has an error, always revoke it.
- token_service()->UpdateCredentials(primary_account_id, "refresh_token");
- ASSERT_FALSE(token_service()->RefreshTokenHasError(primary_account_id));
- token_service()->UpdateAuthErrorForTesting(
- primary_account_id,
+ identity_test_env()->SetRefreshTokenForAccount(primary_account_id);
+ EXPECT_FALSE(
+ identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
+ primary_account_id));
+ identity::UpdatePersistentErrorOfRefreshTokenForAccount(
+ identity_test_env()->identity_manager(), primary_account_id,
GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
GoogleServiceAuthError::InvalidGaiaCredentialsReason::
CREDENTIALS_REJECTED_BY_SERVER));
@@ -1611,8 +1671,8 @@ TEST_F(AccountReconcilorTest, DiceDeleteCookie) {
reconcilor->OnGaiaCookieDeletedByUserAction();
EXPECT_EQ(GoogleServiceAuthError::InvalidGaiaCredentialsReason::
CREDENTIALS_REJECTED_BY_CLIENT,
- token_service()
- ->GetAuthError(primary_account_id)
+ identity_manager
+ ->GetErrorStateOfRefreshTokenForAccount(primary_account_id)
.GetInvalidGaiaCredentialsReason());
}
}
@@ -1687,15 +1747,18 @@ TEST_P(AccountReconcilorTestMirrorMultilogin, TableRowTest) {
std::vector<Token> tokens_before_reconcile =
ParseTokenString(GetParam().tokens);
for (const Token& token : tokens_before_reconcile) {
- std::string account_id = SeedAccountInfo(token.gaia_id, token.email);
- if (token.is_authenticated)
- ConnectProfileToAccount(token.gaia_id, token.email);
- else
- token_service()->UpdateCredentials(account_id, "refresh_token");
+ std::string account_id;
+ if (token.is_authenticated) {
+ account_id = ConnectProfileToAccount(token.email).account_id;
+ } else {
+ account_id = SeedAccountInfo(token.gaia_id, token.email);
+ identity_test_env()->SetRefreshTokenForAccount(account_id);
+ }
if (token.has_error) {
- token_service()->UpdateAuthErrorForTesting(
- account_id, GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ identity::UpdatePersistentErrorOfRefreshTokenForAccount(
+ identity_test_env()->identity_manager(), account_id,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
}
}
VerifyCurrentTokens(tokens_before_reconcile);
@@ -1715,8 +1778,8 @@ TEST_P(AccountReconcilorTestMirrorMultilogin, TableRowTest) {
if (GetParam().gaia_api_calls[i] == 'M') {
std::vector<std::string> accounts_to_send;
for (int i = 0; GetParam().cookies_after_reconcile[i] != '\0'; ++i) {
- std::string account_to_send =
- std::string(1, GetParam().cookies_after_reconcile[i]);
+ char cookie = GetParam().cookies_after_reconcile[i];
+ std::string account_to_send = GaiaIdForAccountKey(cookie);
accounts_to_send.push_back(PickAccountIdForAccount(
account_to_send,
accounts_[GetParam().cookies_after_reconcile[i]].email));
@@ -1769,9 +1832,9 @@ INSTANTIATE_TEST_CASE_P(
// automatically started when tokens are loaded.
TEST_P(AccountReconcilorMirrorEndpointParamTest, TokensNotLoaded) {
const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
+ ConnectProfileToAccount("user@gmail.com").account_id;
cookie_manager_service()->SetListAccountsResponseNoAccounts();
- token_service()->set_all_credentials_loaded_for_testing(false);
+ identity_test_env()->ResetToAccountsNotYetLoadedFromDiskState();
AccountReconcilor* reconcilor = GetMockReconcilor();
reconcilor->StartReconcile();
@@ -1781,7 +1844,7 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, TokensNotLoaded) {
// can start as long as the token service is not empty.
ASSERT_FALSE(reconcilor->is_reconcile_started_);
// When tokens are loaded, reconcile starts automatically.
- token_service()->LoadCredentials(account_id);
+ identity_test_env()->identity_manager()->LegacyLoadCredentials(account_id);
#endif
if (!IsMultiloginEnabled()) {
@@ -1807,11 +1870,11 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, TokensNotLoaded) {
}
TEST_P(AccountReconcilorMirrorEndpointParamTest, GetAccountsFromCookieSuccess) {
- const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ const std::string account_id = account_info.account_id;
cookie_manager_service()->SetListAccountsResponseOneAccountWithParams(
- {"user@gmail.com", "12345", false /* valid */, false /* signed_out */,
- true /* verified */});
+ {account_info.email, account_info.gaia, false /* valid */,
+ false /* signed_out */, true /* verified */});
if (!IsMultiloginEnabled()) {
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
@@ -1842,8 +1905,7 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, GetAccountsFromCookieSuccess) {
}
TEST_P(AccountReconcilorMirrorEndpointParamTest, GetAccountsFromCookieFailure) {
- ;
- ConnectProfileToAccount("12345", "user@gmail.com");
+ ConnectProfileToAccount("user@gmail.com");
cookie_manager_service()->SetListAccountsResponseWebLoginRequired();
AccountReconcilor* reconcilor = GetMockReconcilor();
@@ -1865,15 +1927,62 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, GetAccountsFromCookieFailure) {
ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_ERROR, reconcilor->GetState());
}
+// Regression test for https://crbug.com/923716
+TEST_P(AccountReconcilorMirrorEndpointParamTest,
+ ExtraCookieChangeNotification) {
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ const std::string account_id = account_info.account_id;
+ signin::CookieParams cookie_params = {
+ account_info.email, account_info.gaia, false /* valid */,
+ false /* signed_out */, true /* verified */};
+
+ cookie_manager_service()->SetListAccountsResponseOneAccountWithParams(
+ cookie_params);
+
+ if (!IsMultiloginEnabled()) {
+ EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
+ } else {
+ std::vector<std::string> accounts_to_send = {account_id};
+ const signin::MultiloginParameters params(
+ gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER,
+ accounts_to_send);
+ EXPECT_CALL(*GetMockReconcilor(), PerformSetCookiesAction(params));
+ }
+
+ AccountReconcilor* reconcilor = GetMockReconcilor();
+ ASSERT_TRUE(reconcilor);
+
+ ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_OK, reconcilor->GetState());
+ reconcilor->StartReconcile();
+ ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_RUNNING, reconcilor->GetState());
+
+ // Add extra cookie change notification. Reconcilor should ignore it.
+ gaia::ListedAccount listed_account =
+ ListedAccounfFromCookieParams(cookie_params, account_id);
+ reconcilor->OnGaiaAccountsInCookieUpdated(
+ {listed_account}, {}, GoogleServiceAuthError::AuthErrorNone());
+
+ base::RunLoop().RunUntilIdle();
+
+ if (!IsMultiloginEnabled()) {
+ SimulateAddAccountToCookieCompleted(
+ reconcilor, account_id, GoogleServiceAuthError::AuthErrorNone());
+ } else {
+ SimulateSetAccountsInCookieCompleted(
+ reconcilor, GoogleServiceAuthError::AuthErrorNone());
+ }
+ ASSERT_FALSE(reconcilor->is_reconcile_started_);
+ ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_OK, reconcilor->GetState());
+}
+
TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileNoop) {
- const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
- cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
- "12345");
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ account_info.email, account_info.gaia);
reconcilor->StartReconcile();
ASSERT_TRUE(reconcilor->is_reconcile_started_);
@@ -1893,8 +2002,8 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileNoop) {
TEST_P(AccountReconcilorMirrorEndpointParamTest,
StartReconcileCookiesDisabled) {
const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
- token_service()->UpdateCredentials(account_id, "refresh_token");
+ ConnectProfileToAccount("user@gmail.com").account_id;
+ identity_test_env()->SetRefreshTokenForAccount(account_id);
test_signin_client()->set_are_signin_cookies_allowed(false);
AccountReconcilor* reconcilor = GetMockReconcilor();
@@ -1913,8 +2022,8 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest,
TEST_P(AccountReconcilorMirrorEndpointParamTest,
StartReconcileContentSettings) {
const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
- token_service()->UpdateCredentials(account_id, "refresh_token");
+ ConnectProfileToAccount("user@gmail.com").account_id;
+ identity_test_env()->SetRefreshTokenForAccount(account_id);
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
@@ -1933,8 +2042,8 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest,
TEST_P(AccountReconcilorMirrorEndpointParamTest,
StartReconcileContentSettingsGaiaUrl) {
const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
- token_service()->UpdateCredentials(account_id, "refresh_token");
+ ConnectProfileToAccount("user@gmail.com").account_id;
+ identity_test_env()->SetRefreshTokenForAccount(account_id);
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
@@ -1948,8 +2057,8 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest,
TEST_P(AccountReconcilorMirrorEndpointParamTest,
StartReconcileContentSettingsNonGaiaUrl) {
const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
- token_service()->UpdateCredentials(account_id, "refresh_token");
+ ConnectProfileToAccount("user@gmail.com").account_id;
+ identity_test_env()->SetRefreshTokenForAccount(account_id);
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
@@ -1963,8 +2072,8 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest,
TEST_P(AccountReconcilorMirrorEndpointParamTest,
StartReconcileContentSettingsInvalidPattern) {
const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
- token_service()->UpdateCredentials(account_id, "refresh_token");
+ ConnectProfileToAccount("user@gmail.com").account_id;
+ identity_test_env()->SetRefreshTokenForAccount(account_id);
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
@@ -1991,10 +2100,9 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileNoopWithDots) {
return;
}
- const std::string account_id =
- ConnectProfileToAccount("12345", "Dot.S@gmail.com");
- cookie_manager_service()->SetListAccountsResponseOneAccount("dot.s@gmail.com",
- "12345");
+ AccountInfo account_info = ConnectProfileToAccount("Dot.S@gmail.com");
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ account_info.email, account_info.gaia);
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
@@ -2010,12 +2118,12 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileNoopWithDots) {
}
TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileNoopMultiple) {
- const std::string account_id =
- ConnectProfileToAccount("67890", "user@gmail.com");
- const std::string account_id2 = SeedAccountInfo("12345", "other@gmail.com");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ AccountInfo account_info_2 =
+ identity_test_env()->MakeAccountAvailable("other@gmail.com");
cookie_manager_service()->SetListAccountsResponseTwoAccounts(
- "user@gmail.com", "67890", "other@gmail.com", "12345");
- token_service()->UpdateCredentials(account_id2, "refresh_token");
+ account_info.email, account_info.gaia, account_info_2.email,
+ account_info_2.gaia);
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
@@ -2034,14 +2142,14 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileNoopMultiple) {
}
TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileAddToCookie) {
- const std::string account_id =
- ConnectProfileToAccount("67890", "user@gmail.com");
- token_service()->UpdateCredentials(account_id, "refresh_token");
- cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
- "67890");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ const std::string account_id = account_info.account_id;
+ identity_test_env()->SetRefreshTokenForAccount(account_id);
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ account_info.email, account_info.gaia);
- const std::string account_id2 = SeedAccountInfo("12345", "other@gmail.com");
- token_service()->UpdateCredentials(account_id2, "refresh_token");
+ const std::string account_id2 =
+ identity_test_env()->MakeAccountAvailable("other@gmail.com").account_id;
if (!IsMultiloginEnabled()) {
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
@@ -2108,16 +2216,16 @@ TEST_F(AccountReconcilorTest, AuthErrorTriggersListAccount) {
#endif
// Add one account to Chrome and instantiate the reconcilor.
- const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
- token_service()->UpdateCredentials(account_id, "refresh_token");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ const std::string account_id = account_info.account_id;
+ identity_test_env()->SetRefreshTokenForAccount(account_id);
TestGaiaCookieObserver observer;
cookie_manager_service()->AddObserver(&observer);
AccountReconcilor* reconcilor = GetMockReconcilor();
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(reconcilor->is_reconcile_started_);
- cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
- "12345");
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ account_info.email, account_info.gaia);
if (account_consistency == signin::AccountConsistencyMethod::kDice) {
EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction())
.Times(1);
@@ -2125,10 +2233,11 @@ TEST_F(AccountReconcilorTest, AuthErrorTriggersListAccount) {
// Set an authentication error.
ASSERT_FALSE(observer.cookies_updated_);
- token_service()->UpdateAuthErrorForTesting(
- account_id, GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
- GoogleServiceAuthError::InvalidGaiaCredentialsReason::
- CREDENTIALS_REJECTED_BY_SERVER));
+ identity::UpdatePersistentErrorOfRefreshTokenForAccount(
+ identity_test_env()->identity_manager(), account_id,
+ GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_SERVER));
base::RunLoop().RunUntilIdle();
// Check that a call to ListAccount was triggered.
@@ -2144,14 +2253,14 @@ TEST_F(AccountReconcilorTest, AuthErrorTriggersListAccount) {
TEST_P(AccountReconcilorMirrorEndpointParamTest,
SignoutAfterErrorDoesNotRecordUma) {
- const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
- token_service()->UpdateCredentials(account_id, "refresh_token");
- cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
- "12345");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ const std::string account_id = account_info.account_id;
+ identity_test_env()->SetRefreshTokenForAccount(account_id);
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ account_info.email, account_info.gaia);
- const std::string account_id2 = SeedAccountInfo("67890", "other@gmail.com");
- token_service()->UpdateCredentials(account_id2, "refresh_token");
+ const std::string account_id2 =
+ identity_test_env()->MakeAccountAvailable("other@gmail.com").account_id;
if (!IsMultiloginEnabled()) {
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
@@ -2178,8 +2287,7 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest,
ASSERT_FALSE(reconcilor->is_reconcile_started_);
EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
- signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST,
- signin_metrics::SignoutDelete::IGNORE_METRIC);
+ identity_test_env()->ClearPrimaryAccount();
base::HistogramTester::CountsMap expected_counts;
expected_counts["Signin.Reconciler.Duration.Failure"] = 1;
@@ -2194,11 +2302,11 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest,
TEST_P(AccountReconcilorMirrorEndpointParamTest,
StartReconcileRemoveFromCookie) {
- const std::string account_id =
- ConnectProfileToAccount("67890", "user@gmail.com");
- token_service()->UpdateCredentials(account_id, "refresh_token");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ const std::string account_id = account_info.account_id;
+ identity_test_env()->SetRefreshTokenForAccount(account_id);
cookie_manager_service()->SetListAccountsResponseTwoAccounts(
- "user@gmail.com", "67890", "other@gmail.com", "12345");
+ account_info.email, account_info.gaia, "other@gmail.com", "12345");
if (!IsMultiloginEnabled()) {
EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
@@ -2239,14 +2347,13 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest,
// Check that reconcile is aborted if there is token error on primary account.
TEST_P(AccountReconcilorMirrorEndpointParamTest, TokenErrorOnPrimary) {
- const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
- token_service()->UpdateAuthErrorForTesting(
- account_id,
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ identity::UpdatePersistentErrorOfRefreshTokenForAccount(
+ identity_test_env()->identity_manager(), account_info.account_id,
GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
cookie_manager_service()->SetListAccountsResponseTwoAccounts(
- "user@gmail.com", "12345", "other@gmail.com", "67890");
+ account_info.email, account_info.gaia, "other@gmail.com", "67890");
AccountReconcilor* reconcilor = GetMockReconcilor();
reconcilor->StartReconcile();
@@ -2257,14 +2364,15 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, TokenErrorOnPrimary) {
TEST_P(AccountReconcilorMirrorEndpointParamTest,
StartReconcileAddToCookieTwice) {
- const std::string account_id =
- ConnectProfileToAccount("67890", "user@gmail.com");
- const std::string account_id2 = SeedAccountInfo("12345", "other@gmail.com");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ const std::string account_id = account_info.account_id;
+ AccountInfo account_info2 =
+ identity_test_env()->MakeAccountAvailable("other@gmail.com");
+ const std::string account_id2 = account_info2.account_id;
const std::string account_id3 = SeedAccountInfo("34567", "third@gmail.com");
- cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
- "67890");
- token_service()->UpdateCredentials(account_id2, "refresh_token");
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ account_info.email, account_info.gaia);
if (!IsMultiloginEnabled()) {
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
@@ -2303,11 +2411,12 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest,
// Do another pass after I've added a third account to the token service
cookie_manager_service()->SetListAccountsResponseTwoAccounts(
- "user@gmail.com", "67890", "other@gmail.com", "12345");
+ account_info.email, account_info.gaia, account_info2.email,
+ account_info2.gaia);
cookie_manager_service()->set_list_accounts_stale_for_testing(true);
// This will cause the reconcilor to fire.
- token_service()->UpdateCredentials(account_id3, "refresh_token");
+ identity_test_env()->SetRefreshTokenForAccount(account_id3);
if (IsMultiloginEnabled()) {
std::vector<std::string> accounts_to_send = {account_id, account_id2,
account_id3};
@@ -2347,13 +2456,15 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest,
}
TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileBadPrimary) {
- const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
- const std::string account_id2 = SeedAccountInfo("67890", "other@gmail.com");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ const std::string account_id = account_info.account_id;
- token_service()->UpdateCredentials(account_id2, "refresh_token");
+ AccountInfo account_info2 =
+ identity_test_env()->MakeAccountAvailable("other@gmail.com");
+ const std::string account_id2 = account_info2.account_id;
cookie_manager_service()->SetListAccountsResponseTwoAccounts(
- "other@gmail.com", "67890", "user@gmail.com", "12345");
+ account_info2.email, account_info2.gaia, account_info.email,
+ account_info.gaia);
if (!IsMultiloginEnabled()) {
EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
@@ -2396,10 +2507,9 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileBadPrimary) {
}
TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileOnlyOnce) {
- const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
- cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
- "12345");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ account_info.email, account_info.gaia);
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
@@ -2413,10 +2523,10 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileOnlyOnce) {
}
TEST_P(AccountReconcilorMirrorEndpointParamTest, Lock) {
- const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
- cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
- "12345");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ account_info.email, account_info.gaia);
+
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
ASSERT_FALSE(reconcilor->is_reconcile_started_);
@@ -2487,15 +2597,16 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, Lock) {
TEST_P(AccountReconcilorMethodParamTest,
StartReconcileWithSessionInfoExpiredDefault) {
SetAccountConsistency(GetParam());
- const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
- const std::string account_id2 = SeedAccountInfo("67890", "other@gmail.com");
- token_service()->UpdateCredentials(account_id2, "refresh_token");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ const std::string account_id = account_info.account_id;
+ AccountInfo account_info2 =
+ identity_test_env()->MakeAccountAvailable("other@gmail.com");
+ const std::string account_id2 = account_info2.account_id;
cookie_manager_service()->SetListAccountsResponseWithParams(
- {{"user@gmail.com", "12345", false /* valid */, false /* signed_out */,
- true /* verified */},
- {"other@gmail.com", "67890", true /* valid */, false /* signed_out */,
- true /* verified */}});
+ {{account_info.email, account_info.gaia, false /* valid */,
+ false /* signed_out */, true /* verified */},
+ {account_info2.email, account_info2.gaia, true /* valid */,
+ false /* signed_out */, true /* verified */}});
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
@@ -2514,11 +2625,11 @@ TEST_P(AccountReconcilorMethodParamTest,
TEST_P(AccountReconcilorMirrorEndpointParamTest,
AddAccountToCookieCompletedWithBogusAccount) {
- const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ const std::string account_id = account_info.account_id;
cookie_manager_service()->SetListAccountsResponseOneAccountWithParams(
- {"user@gmail.com", "12345", false /* valid */, false /* signed_out */,
- true /* verified */});
+ {account_info.email, account_info.gaia, false /* valid */,
+ false /* signed_out */, true /* verified */});
if (!IsMultiloginEnabled()) {
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
@@ -2553,10 +2664,11 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest,
TEST_P(AccountReconcilorMirrorEndpointParamTest, NoLoopWithBadPrimary) {
// Connect profile to a primary account and then add a secondary account.
- const std::string account_id1 =
- ConnectProfileToAccount("12345", "user@gmail.com");
- const std::string account_id2 = SeedAccountInfo("67890", "other@gmail.com");
- token_service()->UpdateCredentials(account_id2, "refresh_token");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ const std::string account_id1 = account_info.account_id;
+ AccountInfo account_info2 =
+ identity_test_env()->MakeAccountAvailable("other@gmail.com");
+ const std::string account_id2 = account_info2.account_id;
if (!IsMultiloginEnabled()) {
EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
@@ -2571,8 +2683,8 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, NoLoopWithBadPrimary) {
}
// The primary account is in auth error, so it is not in the cookie.
cookie_manager_service()->SetListAccountsResponseOneAccountWithParams(
- {"other@gmail.com", "67890", false /* valid */, false /* signed_out */,
- true /* verified */});
+ {account_info2.email, account_info2.gaia, false /* valid */,
+ false /* signed_out */, true /* verified */});
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
@@ -2600,7 +2712,8 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, NoLoopWithBadPrimary) {
// Now that we've tried once, the token service knows that the primary
// account has an auth error.
- token_service()->UpdateAuthErrorForTesting(account_id1, error);
+ identity::UpdatePersistentErrorOfRefreshTokenForAccount(
+ identity_test_env()->identity_manager(), account_id1, error);
// A second attempt to reconcile should be a noop.
reconcilor->StartReconcile();
@@ -2612,13 +2725,13 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, NoLoopWithBadPrimary) {
TEST_P(AccountReconcilorMirrorEndpointParamTest, WontMergeAccountsWithError) {
// Connect profile to a primary account and then add a secondary account.
const std::string account_id1 =
- ConnectProfileToAccount("12345", "user@gmail.com");
- const std::string account_id2 = SeedAccountInfo("67890", "other@gmail.com");
- token_service()->UpdateCredentials(account_id2, "refresh_token");
+ ConnectProfileToAccount("user@gmail.com").account_id;
+ const std::string account_id2 =
+ identity_test_env()->MakeAccountAvailable("other@gmail.com").account_id;
// Mark the secondary account in auth error state.
- token_service()->UpdateAuthErrorForTesting(
- account_id2,
+ identity::UpdatePersistentErrorOfRefreshTokenForAccount(
+ identity_test_env()->identity_manager(), account_id2,
GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
// The cookie starts empty.
@@ -2660,8 +2773,7 @@ TEST_P(AccountReconcilorMirrorEndpointParamTest, WontMergeAccountsWithError) {
// Test that delegate timeout is called when the delegate offers a valid
// timeout.
TEST_F(AccountReconcilorTest, DelegateTimeoutIsCalled) {
- const std::string account_id =
- ConnectProfileToAccount("12345", "user@gmail.com");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
auto spy_delegate0 = std::make_unique<SpyReconcilorDelegate>();
SpyReconcilorDelegate* spy_delegate = spy_delegate0.get();
AccountReconcilor* reconcilor = GetMockReconcilor(std::move(spy_delegate0));
@@ -2684,9 +2796,9 @@ TEST_F(AccountReconcilorTest, DelegateTimeoutIsCalled) {
// Test that delegate timeout is not called when the delegate does not offer a
// valid timeout.
TEST_P(AccountReconcilorMirrorEndpointParamTest, DelegateTimeoutIsNotCalled) {
- ConnectProfileToAccount("12345", "user@gmail.com");
- cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
- "12345");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ account_info.email, account_info.gaia);
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
auto timer0 = std::make_unique<base::MockOneShotTimer>();
@@ -2703,9 +2815,9 @@ INSTANTIATE_TEST_CASE_P(TestMirrorEndpoint,
::testing::ValuesIn({false, true}));
TEST_F(AccountReconcilorTest, DelegateTimeoutIsNotCalledIfTimeoutIsNotReached) {
- ConnectProfileToAccount("12345", "user@gmail.com");
- cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
- "12345");
+ AccountInfo account_info = ConnectProfileToAccount("user@gmail.com");
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ account_info.email, account_info.gaia);
auto spy_delegate0 = std::make_unique<SpyReconcilorDelegate>();
SpyReconcilorDelegate* spy_delegate = spy_delegate0.get();
AccountReconcilor* reconcilor = GetMockReconcilor(std::move(spy_delegate0));
@@ -2732,3 +2844,10 @@ TEST_F(AccountReconcilorTest, ScopedSyncedDataDeletionDestructionOrder) {
DeleteReconcilor();
// data_deletion is destroyed after the reconcilor, this should not crash.
}
+
+TEST_F(AccountReconcilorTest, LockDestructionOrder) {
+ AccountReconcilor* reconcilor = GetMockReconcilor();
+ AccountReconcilor::Lock lock(reconcilor);
+ DeleteReconcilor();
+ // |lock| is destroyed after the reconcilor, this should not crash.
+}
diff --git a/chromium/components/signin/core/browser/account_tracker_service.cc b/chromium/components/signin/core/browser/account_tracker_service.cc
index 51c45a8888f..0526b0e94c6 100644
--- a/chromium/components/signin/core/browser/account_tracker_service.cc
+++ b/chromium/components/signin/core/browser/account_tracker_service.cc
@@ -22,9 +22,15 @@
#include "build/build_config.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/scoped_user_pref_update.h"
+#include "components/signin/core/browser/account_info_util.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/core/browser/signin_pref_names.h"
+#if defined(OS_ANDROID)
+#include "base/android/jni_array.h"
+#include "jni/AccountTrackerService_jni.h"
+#endif
+
namespace {
const char kAccountKeyPath[] = "account_id";
@@ -39,6 +45,10 @@ const char kAccountChildAccountStatusPath[] = "is_child_account";
const char kAdvancedProtectionAccountStatusPath[] =
"is_under_advanced_protection";
+// TODO(knn): Remove once deprecated service flags have been migrated from
+// preferences.
+const char kChildAccountServiceFlag[] = "uca";
+
// Account folders used for storing account related data at disk.
const base::FilePath::CharType kAccountsFolder[] =
FILE_PATH_LITERAL("Accounts");
@@ -49,7 +59,7 @@ const base::FilePath::CharType kAvatarImagesFolder[] =
const char kAccountServiceFlagsPath[] = "service_flags";
void RemoveDeprecatedServiceFlags(PrefService* pref_service) {
- ListPrefUpdate update(pref_service, AccountTrackerService::kAccountInfoPref);
+ ListPrefUpdate update(pref_service, prefs::kAccountInfo);
for (size_t i = 0; i < update->GetSize(); ++i) {
base::DictionaryValue* dict = nullptr;
if (update->GetDictionary(i, &dict))
@@ -97,17 +107,14 @@ void RemoveImage(const base::FilePath& image_path) {
} // namespace
-const char AccountTrackerService::kAccountInfoPref[] = "account_info";
-
-const char AccountTrackerService::kChildAccountServiceFlag[] = "uca";
-
-// This must be a string which can never be a valid domain.
-const char AccountTrackerService::kNoHostedDomainFound[] = "NO_HOSTED_DOMAIN";
-
-// This must be a string which can never be a valid picture URL.
-const char AccountTrackerService::kNoPictureURLFound[] = "NO_PICTURE_URL";
-
-AccountTrackerService::AccountTrackerService() : weak_factory_(this) {}
+AccountTrackerService::AccountTrackerService() : weak_factory_(this) {
+#if defined(OS_ANDROID)
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jobject> java_ref =
+ Java_AccountTrackerService_create(env, reinterpret_cast<intptr_t>(this));
+ java_ref_.Reset(env, java_ref.obj());
+#endif
+}
AccountTrackerService::~AccountTrackerService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -115,7 +122,7 @@ AccountTrackerService::~AccountTrackerService() {
// static
void AccountTrackerService::RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterListPref(AccountTrackerService::kAccountInfoPref);
+ registry->RegisterListPref(prefs::kAccountInfo);
registry->RegisterIntegerPref(prefs::kAccountIdMigrationState,
AccountTrackerService::MIGRATION_NOT_STARTED);
}
@@ -153,7 +160,7 @@ void AccountTrackerService::RemoveObserver(Observer* observer) {
std::vector<AccountInfo> AccountTrackerService::GetAccounts() const {
std::vector<AccountInfo> accounts;
for (const auto& pair : accounts_) {
- accounts.push_back(pair.second.info);
+ accounts.push_back(pair.second);
}
return accounts;
}
@@ -162,7 +169,7 @@ AccountInfo AccountTrackerService::GetAccountInfo(
const std::string& account_id) const {
const auto iterator = accounts_.find(account_id);
if (iterator != accounts_.end())
- return iterator->second.info;
+ return iterator->second;
return AccountInfo();
}
@@ -171,11 +178,10 @@ AccountInfo AccountTrackerService::FindAccountInfoByGaiaId(
const std::string& gaia_id) const {
if (!gaia_id.empty()) {
const auto iterator = std::find_if(
- accounts_.begin(), accounts_.end(), [&gaia_id](const auto& pair) {
- return pair.second.info.gaia == gaia_id;
- });
+ accounts_.begin(), accounts_.end(),
+ [&gaia_id](const auto& pair) { return pair.second.gaia == gaia_id; });
if (iterator != accounts_.end())
- return iterator->second.info;
+ return iterator->second;
}
return AccountInfo();
@@ -186,24 +192,15 @@ AccountInfo AccountTrackerService::FindAccountInfoByEmail(
if (!email.empty()) {
const auto iterator = std::find_if(
accounts_.begin(), accounts_.end(), [&email](const auto& pair) {
- return gaia::AreEmailsSame(pair.second.info.email, email);
+ return gaia::AreEmailsSame(pair.second.email, email);
});
if (iterator != accounts_.end())
- return iterator->second.info;
+ return iterator->second;
}
return AccountInfo();
}
-gfx::Image AccountTrackerService::GetAccountImage(
- const std::string& account_id) {
- const auto iterator = accounts_.find(account_id);
- if (iterator != accounts_.end())
- return iterator->second.image;
-
- return gfx::Image();
-}
-
// static
bool AccountTrackerService::IsMigrationSupported() {
#if defined(OS_CHROMEOS)
@@ -222,17 +219,11 @@ void AccountTrackerService::SetMigrationDone() {
SetMigrationState(MIGRATION_DONE);
}
-void AccountTrackerService::NotifyAccountUpdated(const AccountState& state) {
- DCHECK(!state.info.gaia.empty());
- for (auto& observer : observer_list_)
- observer.OnAccountUpdated(state.info);
-}
-
-void AccountTrackerService::NotifyAccountImageUpdated(
- const std::string& account_id,
- const gfx::Image& image) {
+void AccountTrackerService::NotifyAccountUpdated(
+ const AccountInfo& account_info) {
+ DCHECK(!account_info.gaia.empty());
for (auto& observer : observer_list_)
- observer.OnAccountImageUpdated(account_id, image);
+ observer.OnAccountUpdated(account_info);
}
void AccountTrackerService::NotifyAccountUpdateFailed(
@@ -241,113 +232,103 @@ void AccountTrackerService::NotifyAccountUpdateFailed(
observer.OnAccountUpdateFailed(account_id);
}
-void AccountTrackerService::NotifyAccountRemoved(const AccountState& state) {
- DCHECK(!state.info.gaia.empty());
+void AccountTrackerService::NotifyAccountRemoved(
+ const AccountInfo& account_info) {
+ DCHECK(!account_info.gaia.empty());
for (auto& observer : observer_list_)
- observer.OnAccountRemoved(state.info);
+ observer.OnAccountRemoved(account_info);
}
void AccountTrackerService::StartTrackingAccount(
const std::string& account_id) {
if (!base::ContainsKey(accounts_, account_id)) {
DVLOG(1) << "StartTracking " << account_id;
- AccountState state;
- state.info.account_id = account_id;
- state.info.is_child_account = false;
- accounts_.insert(make_pair(account_id, state));
+ AccountInfo account_info;
+ account_info.account_id = account_id;
+ account_info.is_child_account = false;
+ accounts_.insert(make_pair(account_id, account_info));
}
}
void AccountTrackerService::StopTrackingAccount(const std::string& account_id) {
DVLOG(1) << "StopTracking " << account_id;
if (base::ContainsKey(accounts_, account_id)) {
- AccountState state = std::move(accounts_[account_id]);
- RemoveFromPrefs(state);
+ AccountInfo account_info = std::move(accounts_[account_id]);
+ RemoveFromPrefs(account_info);
RemoveAccountImageFromDisk(account_id);
accounts_.erase(account_id);
- if (!state.info.gaia.empty())
- NotifyAccountRemoved(state);
+ if (!account_info.gaia.empty())
+ NotifyAccountRemoved(account_info);
}
}
-void AccountTrackerService::SetAccountStateFromUserInfo(
+void AccountTrackerService::SetAccountInfoFromUserInfo(
const std::string& account_id,
const base::DictionaryValue* user_info) {
DCHECK(base::ContainsKey(accounts_, account_id));
- AccountState& state = accounts_[account_id];
-
- std::string gaia_id;
- std::string email;
- if (user_info->GetString("id", &gaia_id) &&
- user_info->GetString("email", &email)) {
- state.info.gaia = gaia_id;
- state.info.email = email;
-
- std::string hosted_domain;
- if (user_info->GetString("hd", &hosted_domain) && !hosted_domain.empty()) {
- state.info.hosted_domain = hosted_domain;
- } else {
- state.info.hosted_domain = kNoHostedDomainFound;
- }
-
- user_info->GetString("name", &state.info.full_name);
- user_info->GetString("given_name", &state.info.given_name);
- user_info->GetString("locale", &state.info.locale);
-
- std::string picture_url;
- if (user_info->GetString("picture", &picture_url)) {
- state.info.picture_url = picture_url;
- } else {
- state.info.picture_url = kNoPictureURLFound;
- }
+ AccountInfo& account_info = accounts_[account_id];
+
+ base::Optional<AccountInfo> maybe_account_info =
+ AccountInfoFromUserInfo(*user_info);
+ if (maybe_account_info) {
+ // Should we DCHECK that the account stored in |accounts_| has the same
+ // value for |gaia_id| and |email| as the value loaded from |user_info|?
+ // DCHECK(account_info.gaia.empty()
+ // || account_info.gaia == maybe_account_info.value().gaia);
+ // DCHECK(account_info.email.empty()
+ // || account_info.email == maybe_account_info.value().email);
+ maybe_account_info.value().account_id = account_id;
+ account_info.UpdateWith(maybe_account_info.value());
}
- if (!state.info.gaia.empty())
- NotifyAccountUpdated(state);
- SaveToPrefs(state);
+
+ if (!account_info.gaia.empty())
+ NotifyAccountUpdated(account_info);
+ SaveToPrefs(account_info);
}
void AccountTrackerService::SetAccountImage(const std::string& account_id,
const gfx::Image& image) {
if (!base::ContainsKey(accounts_, account_id))
return;
- accounts_[account_id].image = image;
+ AccountInfo& account_info = accounts_[account_id];
+ account_info.account_image = image;
SaveAccountImageToDisk(account_id, image);
- NotifyAccountImageUpdated(account_id, image);
+ NotifyAccountUpdated(account_info);
}
void AccountTrackerService::SetIsChildAccount(const std::string& account_id,
bool is_child_account) {
DCHECK(base::ContainsKey(accounts_, account_id));
- AccountState& state = accounts_[account_id];
- if (state.info.is_child_account == is_child_account)
+ AccountInfo& account_info = accounts_[account_id];
+ if (account_info.is_child_account == is_child_account)
return;
- state.info.is_child_account = is_child_account;
- if (!state.info.gaia.empty())
- NotifyAccountUpdated(state);
- SaveToPrefs(state);
+ account_info.is_child_account = is_child_account;
+ if (!account_info.gaia.empty())
+ NotifyAccountUpdated(account_info);
+ SaveToPrefs(account_info);
}
void AccountTrackerService::SetIsAdvancedProtectionAccount(
const std::string& account_id,
bool is_under_advanced_protection) {
DCHECK(base::ContainsKey(accounts_, account_id));
- AccountState& state = accounts_[account_id];
- if (state.info.is_under_advanced_protection == is_under_advanced_protection)
+ AccountInfo& account_info = accounts_[account_id];
+ if (account_info.is_under_advanced_protection == is_under_advanced_protection)
return;
- state.info.is_under_advanced_protection = is_under_advanced_protection;
- if (!state.info.gaia.empty())
- NotifyAccountUpdated(state);
- SaveToPrefs(state);
+ account_info.is_under_advanced_protection = is_under_advanced_protection;
+ if (!account_info.gaia.empty())
+ NotifyAccountUpdated(account_info);
+ SaveToPrefs(account_info);
}
void AccountTrackerService::MigrateToGaiaId() {
DCHECK_EQ(GetMigrationState(), MIGRATION_IN_PROGRESS);
std::vector<std::string> to_remove;
- std::vector<AccountState> migrated_accounts;
+ std::vector<AccountInfo> migrated_accounts;
for (const auto& pair : accounts_) {
- const std::string& new_account_id = pair.second.info.gaia;
+ const std::string& new_account_id = pair.second.gaia;
if (pair.first == new_account_id)
continue;
@@ -359,28 +340,28 @@ void AccountTrackerService::MigrateToGaiaId() {
if (base::ContainsKey(accounts_, new_account_id))
continue;
- AccountState new_state = pair.second;
- new_state.info.account_id = new_account_id;
- SaveToPrefs(new_state);
- migrated_accounts.emplace_back(std::move(new_state));
+ AccountInfo new_account_info = pair.second;
+ new_account_info.account_id = new_account_id;
+ SaveToPrefs(new_account_info);
+ migrated_accounts.emplace_back(std::move(new_account_info));
}
// Insert the new migrated accounts.
- for (AccountState& new_state : migrated_accounts) {
- // Copy the AccountState |gaia| member field so that it is not left in
+ for (AccountInfo& new_account_info : migrated_accounts) {
+ // Copy the AccountInfo |gaia| member field so that it is not left in
// an undeterminate state in the structure after std::map::emplace call.
- std::string account_id = new_state.info.gaia;
- SaveToPrefs(new_state);
+ std::string account_id = new_account_info.gaia;
+ SaveToPrefs(new_account_info);
- accounts_.emplace(std::move(account_id), std::move(new_state));
+ accounts_.emplace(std::move(account_id), std::move(new_account_info));
}
// Remove any obsolete account.
for (const auto& account_id : to_remove) {
DCHECK(base::ContainsKey(accounts_, account_id));
- AccountState& state = accounts_[account_id];
+ AccountInfo& account_info = accounts_[account_id];
RemoveAccountImageFromDisk(account_id);
- RemoveFromPrefs(state);
+ RemoveFromPrefs(account_info);
accounts_.erase(account_id);
}
}
@@ -390,7 +371,7 @@ bool AccountTrackerService::IsMigrationDone() const {
return false;
for (const auto& pair : accounts_) {
- if (pair.first != pair.second.info.gaia)
+ if (pair.first != pair.second.gaia)
return false;
}
@@ -406,12 +387,12 @@ AccountTrackerService::ComputeNewMigrationState() const {
bool migration_required = false;
for (const auto& pair : accounts_) {
// If there is any non-migratable account, skip migration.
- if (pair.first.empty() || pair.second.info.gaia.empty())
+ if (pair.first.empty() || pair.second.gaia.empty())
return MIGRATION_NOT_STARTED;
// Migration is required if at least one account is not keyed to its
// gaia id.
- migration_required |= (pair.first != pair.second.info.gaia);
+ migration_required |= (pair.first != pair.second.gaia);
}
return migration_required ? MIGRATION_IN_PROGRESS : MIGRATION_DONE;
@@ -439,9 +420,10 @@ base::FilePath AccountTrackerService::GetImagePathFor(
void AccountTrackerService::OnAccountImageLoaded(const std::string& account_id,
gfx::Image image) {
if (base::ContainsKey(accounts_, account_id) &&
- accounts_[account_id].image.IsEmpty()) {
- accounts_[account_id].image = image;
- NotifyAccountImageUpdated(account_id, image);
+ accounts_[account_id].account_image.IsEmpty()) {
+ AccountInfo& account_info = accounts_[account_id];
+ account_info.account_image = image;
+ NotifyAccountUpdated(account_info);
}
}
@@ -449,7 +431,7 @@ void AccountTrackerService::LoadAccountImagesFromDisk() {
if (!image_storage_task_runner_)
return;
for (const auto& pair : accounts_) {
- const std::string& account_id = pair.second.info.account_id;
+ const std::string& account_id = pair.second.account_id;
PostTaskAndReplyWithResult(
image_storage_task_runner_.get(), FROM_HERE,
base::BindOnce(&ReadImage, GetImagePathFor(account_id)),
@@ -477,7 +459,7 @@ void AccountTrackerService::RemoveAccountImageFromDisk(
}
void AccountTrackerService::LoadFromPrefs() {
- const base::ListValue* list = pref_service_->GetList(kAccountInfoPref);
+ const base::ListValue* list = pref_service_->GetList(prefs::kAccountInfo);
std::set<std::string> to_remove;
bool contains_deprecated_service_flags = false;
for (size_t i = 0; i < list->GetSize(); ++i) {
@@ -495,22 +477,22 @@ void AccountTrackerService::LoadFromPrefs() {
}
StartTrackingAccount(account_id);
- AccountState& state = accounts_[account_id];
+ AccountInfo& account_info = accounts_[account_id];
if (dict->GetString(kAccountGaiaPath, &value))
- state.info.gaia = base::UTF16ToUTF8(value);
+ account_info.gaia = base::UTF16ToUTF8(value);
if (dict->GetString(kAccountEmailPath, &value))
- state.info.email = base::UTF16ToUTF8(value);
+ account_info.email = base::UTF16ToUTF8(value);
if (dict->GetString(kAccountHostedDomainPath, &value))
- state.info.hosted_domain = base::UTF16ToUTF8(value);
+ account_info.hosted_domain = base::UTF16ToUTF8(value);
if (dict->GetString(kAccountFullNamePath, &value))
- state.info.full_name = base::UTF16ToUTF8(value);
+ account_info.full_name = base::UTF16ToUTF8(value);
if (dict->GetString(kAccountGivenNamePath, &value))
- state.info.given_name = base::UTF16ToUTF8(value);
+ account_info.given_name = base::UTF16ToUTF8(value);
if (dict->GetString(kAccountLocalePath, &value))
- state.info.locale = base::UTF16ToUTF8(value);
+ account_info.locale = base::UTF16ToUTF8(value);
if (dict->GetString(kAccountPictureURLPath, &value))
- state.info.picture_url = base::UTF16ToUTF8(value);
+ account_info.picture_url = base::UTF16ToUTF8(value);
bool is_child_account = false;
// Migrate deprecated service flag preference.
@@ -525,20 +507,20 @@ void AccountTrackerService::LoadFromPrefs() {
break;
}
}
- state.info.is_child_account = is_child_account;
+ account_info.is_child_account = is_child_account;
}
if (dict->GetBoolean(kAccountChildAccountStatusPath, &is_child_account))
- state.info.is_child_account = is_child_account;
+ account_info.is_child_account = is_child_account;
bool is_under_advanced_protection = false;
if (dict->GetBoolean(kAdvancedProtectionAccountStatusPath,
&is_under_advanced_protection)) {
- state.info.is_under_advanced_protection =
+ account_info.is_under_advanced_protection =
is_under_advanced_protection;
}
- if (!state.info.gaia.empty())
- NotifyAccountUpdated(state);
+ if (!account_info.gaia.empty())
+ NotifyAccountUpdated(account_info);
}
}
}
@@ -551,9 +533,9 @@ void AccountTrackerService::LoadFromPrefs() {
// Remove any obsolete prefs.
for (auto account_id : to_remove) {
- AccountState state;
- state.info.account_id = account_id;
- RemoveFromPrefs(state);
+ AccountInfo account_info;
+ account_info.account_id = account_id;
+ RemoveFromPrefs(account_info);
RemoveAccountImageFromDisk(account_id);
}
@@ -582,13 +564,13 @@ void AccountTrackerService::LoadFromPrefs() {
accounts_.size());
}
-void AccountTrackerService::SaveToPrefs(const AccountState& state) {
+void AccountTrackerService::SaveToPrefs(const AccountInfo& account_info) {
if (!pref_service_)
return;
base::DictionaryValue* dict = nullptr;
- base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id);
- ListPrefUpdate update(pref_service_, kAccountInfoPref);
+ base::string16 account_id_16 = base::UTF8ToUTF16(account_info.account_id);
+ ListPrefUpdate update(pref_service_, prefs::kAccountInfo);
for (size_t i = 0; i < update->GetSize(); ++i, dict = nullptr) {
if (update->GetDictionary(i, &dict)) {
base::string16 value;
@@ -605,24 +587,25 @@ void AccountTrackerService::SaveToPrefs(const AccountState& state) {
dict->SetString(kAccountKeyPath, account_id_16);
}
- dict->SetString(kAccountEmailPath, state.info.email);
- dict->SetString(kAccountGaiaPath, state.info.gaia);
- dict->SetString(kAccountHostedDomainPath, state.info.hosted_domain);
- dict->SetString(kAccountFullNamePath, state.info.full_name);
- dict->SetString(kAccountGivenNamePath, state.info.given_name);
- dict->SetString(kAccountLocalePath, state.info.locale);
- dict->SetString(kAccountPictureURLPath, state.info.picture_url);
- dict->SetBoolean(kAccountChildAccountStatusPath, state.info.is_child_account);
+ dict->SetString(kAccountEmailPath, account_info.email);
+ dict->SetString(kAccountGaiaPath, account_info.gaia);
+ dict->SetString(kAccountHostedDomainPath, account_info.hosted_domain);
+ dict->SetString(kAccountFullNamePath, account_info.full_name);
+ dict->SetString(kAccountGivenNamePath, account_info.given_name);
+ dict->SetString(kAccountLocalePath, account_info.locale);
+ dict->SetString(kAccountPictureURLPath, account_info.picture_url);
+ dict->SetBoolean(kAccountChildAccountStatusPath,
+ account_info.is_child_account);
dict->SetBoolean(kAdvancedProtectionAccountStatusPath,
- state.info.is_under_advanced_protection);
+ account_info.is_under_advanced_protection);
}
-void AccountTrackerService::RemoveFromPrefs(const AccountState& state) {
+void AccountTrackerService::RemoveFromPrefs(const AccountInfo& account_info) {
if (!pref_service_)
return;
- base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id);
- ListPrefUpdate update(pref_service_, kAccountInfoPref);
+ base::string16 account_id_16 = base::UTF8ToUTF16(account_info.account_id);
+ ListPrefUpdate update(pref_service_, prefs::kAccountInfo);
for (size_t i = 0; i < update->GetSize(); ++i) {
base::DictionaryValue* dict = nullptr;
if (update->GetDictionary(i, &dict)) {
@@ -670,11 +653,12 @@ std::string AccountTrackerService::SeedAccountInfo(const std::string& gaia,
const std::string account_id = PickAccountIdForAccount(gaia, email);
const bool already_exists = base::ContainsKey(accounts_, account_id);
StartTrackingAccount(account_id);
- AccountState& state = accounts_[account_id];
- DCHECK(!already_exists || state.info.gaia.empty() || state.info.gaia == gaia);
- state.info.gaia = gaia;
- state.info.email = email;
- SaveToPrefs(state);
+ AccountInfo& account_info = accounts_[account_id];
+ DCHECK(!already_exists || account_info.gaia.empty() ||
+ account_info.gaia == gaia);
+ account_info.gaia = gaia;
+ account_info.email = email;
+ SaveToPrefs(account_info);
DVLOG(1) << "AccountTrackerService::SeedAccountInfo"
<< " account_id=" << account_id << " gaia_id=" << gaia
@@ -690,13 +674,13 @@ std::string AccountTrackerService::SeedAccountInfo(AccountInfo info) {
StartTrackingAccount(info.account_id);
}
- AccountState& state = accounts_[info.account_id];
- // Update the missing fields in |state.info| with |info|.
- if (state.info.UpdateWith(info)) {
- if (!state.info.gaia.empty())
- NotifyAccountUpdated(state);
+ AccountInfo& account_info = accounts_[info.account_id];
+ // Update the missing fields in |account_info| with |info|.
+ if (account_info.UpdateWith(info)) {
+ if (!account_info.gaia.empty())
+ NotifyAccountUpdated(account_info);
- SaveToPrefs(state);
+ SaveToPrefs(account_info);
}
return info.account_id;
}
@@ -704,3 +688,61 @@ std::string AccountTrackerService::SeedAccountInfo(AccountInfo info) {
void AccountTrackerService::RemoveAccount(const std::string& account_id) {
StopTrackingAccount(account_id);
}
+
+#if defined(OS_ANDROID)
+base::android::ScopedJavaLocalRef<jobject>
+AccountTrackerService::GetJavaObject() {
+ return base::android::ScopedJavaLocalRef<jobject>(java_ref_);
+}
+
+void JNI_AccountTrackerService_SeedAccountsInfo(
+ JNIEnv* env,
+ jlong nativeAccountTrackerService,
+ const base::android::JavaParamRef<jobjectArray>& gaiaIds,
+ const base::android::JavaParamRef<jobjectArray>& accountNames) {
+ AccountTrackerService* service =
+ reinterpret_cast<AccountTrackerService*>(nativeAccountTrackerService);
+ DCHECK(service);
+
+ std::vector<std::string> gaia_ids;
+ std::vector<std::string> account_names;
+ base::android::AppendJavaStringArrayToStringVector(env, gaiaIds, &gaia_ids);
+ base::android::AppendJavaStringArrayToStringVector(env, accountNames,
+ &account_names);
+ DCHECK_EQ(gaia_ids.size(), account_names.size());
+
+ DVLOG(1) << "AccountTrackerService.SeedAccountsInfo: "
+ << " number of accounts " << gaia_ids.size();
+ for (size_t i = 0; i < gaia_ids.size(); ++i) {
+ service->SeedAccountInfo(gaia_ids[i], account_names[i]);
+ }
+}
+
+jboolean JNI_AccountTrackerService_AreAccountsSeeded(
+ JNIEnv* env,
+ jlong nativeAccountTrackerService,
+ const base::android::JavaParamRef<jobjectArray>& accountNames) {
+ AccountTrackerService* service =
+ reinterpret_cast<AccountTrackerService*>(nativeAccountTrackerService);
+ DCHECK(service);
+
+ std::vector<std::string> account_names;
+ base::android::AppendJavaStringArrayToStringVector(env, accountNames,
+ &account_names);
+
+ bool migrated =
+ service->GetMigrationState() ==
+ AccountTrackerService::AccountIdMigrationState::MIGRATION_DONE;
+
+ for (const auto& account_name : account_names) {
+ AccountInfo info = service->FindAccountInfoByEmail(account_name);
+ if (info.account_id.empty()) {
+ return false;
+ }
+ if (migrated && info.gaia.empty()) {
+ return false;
+ }
+ }
+ return true;
+}
+#endif
diff --git a/chromium/components/signin/core/browser/account_tracker_service.h b/chromium/components/signin/core/browser/account_tracker_service.h
index caf69224f86..c60a555a0ba 100644
--- a/chromium/components/signin/core/browser/account_tracker_service.h
+++ b/chromium/components/signin/core/browser/account_tracker_service.h
@@ -16,11 +16,16 @@
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/timer/timer.h"
+#include "build/build_config.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/signin/core/browser/account_info.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "ui/gfx/image/image.h"
+#if defined(OS_ANDROID)
+#include "base/android/scoped_java_ref.h"
+#endif
+
class PrefRegistrySimple;
class PrefService;
@@ -32,30 +37,12 @@ class DictionaryValue;
// information about Google Accounts.
class AccountTrackerService : public KeyedService {
public:
- // Name of the preference property that persists the account information
- // tracked by this service.
- static const char kAccountInfoPref[];
-
- // Value representing no hosted domain in the kGoogleServicesHostedDomain
- // preference.
- static const char kNoHostedDomainFound[];
-
- // Value representing no picture URL associated with an account.
- static const char kNoPictureURLFound[];
-
- // TODO(knn): Move to ChildAccountInfoFetcher once deprecated service flags
- // have been migrated from preferences.
- // Child account service flag name.
- static const char kChildAccountServiceFlag[];
-
// Clients of AccountTrackerService can implement this interface and register
// with AddObserver() to learn about account information changes.
class Observer {
public:
virtual ~Observer() {}
virtual void OnAccountUpdated(const AccountInfo& info) {}
- virtual void OnAccountImageUpdated(const std::string& account_id,
- const gfx::Image& image) {}
virtual void OnAccountUpdateFailed(const std::string& account_id) {}
virtual void OnAccountRemoved(const AccountInfo& info) {}
};
@@ -95,10 +82,6 @@ class AccountTrackerService : public KeyedService {
AccountInfo FindAccountInfoByGaiaId(const std::string& gaia_id) const;
AccountInfo FindAccountInfoByEmail(const std::string& email) const;
- // Returns the account image associated to the account id |account_id|.
- // If the account id is not known an empty image is returned.
- gfx::Image GetAccountImage(const std::string& account_id);
-
// Picks the correct account_id for the specified account depending on the
// migration state.
std::string PickAccountIdForAccount(const std::string& gaia,
@@ -134,10 +117,15 @@ class AccountTrackerService : public KeyedService {
AccountIdMigrationState GetMigrationState() const;
void SetMigrationDone();
+#if defined(OS_ANDROID)
+ // Returns a reference to the corresponding Java AccountTrackerService object.
+ base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
+#endif
+
protected:
// Available to be called in tests.
- void SetAccountStateFromUserInfo(const std::string& account_id,
- const base::DictionaryValue* user_info);
+ void SetAccountInfoFromUserInfo(const std::string& account_id,
+ const base::DictionaryValue* user_info);
// Updates the account image. Does nothing if |account_id| does not exist in
// |accounts_|.
@@ -146,24 +134,18 @@ class AccountTrackerService : public KeyedService {
private:
friend class AccountFetcherService;
friend class FakeAccountFetcherService;
- struct AccountState {
- AccountInfo info;
- gfx::Image image;
- };
- void NotifyAccountUpdated(const AccountState& state);
- void NotifyAccountImageUpdated(const std::string& account_id,
- const gfx::Image& image);
+ void NotifyAccountUpdated(const AccountInfo& account_info);
void NotifyAccountUpdateFailed(const std::string& account_id);
- void NotifyAccountRemoved(const AccountState& state);
+ void NotifyAccountRemoved(const AccountInfo& accoint_info);
void StartTrackingAccount(const std::string& account_id);
void StopTrackingAccount(const std::string& account_id);
// Load the current state of the account info from the preferences file.
void LoadFromPrefs();
- void SaveToPrefs(const AccountState& account);
- void RemoveFromPrefs(const AccountState& account);
+ void SaveToPrefs(const AccountInfo& account);
+ void RemoveFromPrefs(const AccountInfo& account);
// Used to load/save account images from/to disc.
base::FilePath GetImagePathFor(const std::string& account_id);
@@ -194,7 +176,7 @@ class AccountTrackerService : public KeyedService {
const PrefService* pref_service);
PrefService* pref_service_ = nullptr; // Not owned.
- std::map<std::string, AccountState> accounts_;
+ std::map<std::string, AccountInfo> accounts_;
base::ObserverList<Observer>::Unchecked observer_list_;
base::FilePath user_data_dir_;
@@ -202,6 +184,11 @@ class AccountTrackerService : public KeyedService {
// Task runner used for file operations on avatar images.
scoped_refptr<base::SequencedTaskRunner> image_storage_task_runner_;
+#if defined(OS_ANDROID)
+ // A reference to the Java counterpart of this object.
+ base::android::ScopedJavaGlobalRef<jobject> java_ref_;
+#endif
+
SEQUENCE_CHECKER(sequence_checker_);
// Used to pass weak pointers of |this| to tasks created by
diff --git a/chromium/components/signin/core/browser/account_tracker_service_unittest.cc b/chromium/components/signin/core/browser/account_tracker_service_unittest.cc
index e796e3c27d2..2aac21e39b0 100644
--- a/chromium/components/signin/core/browser/account_tracker_service_unittest.cc
+++ b/chromium/components/signin/core/browser/account_tracker_service_unittest.cc
@@ -21,7 +21,6 @@
#include "components/signin/core/browser/account_info.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/avatar_icon_util.h"
-#include "components/signin/core/browser/child_account_info_fetcher.h"
#include "components/signin/core/browser/fake_account_fetcher_service.h"
#include "components/signin/core/browser/signin_pref_names.h"
#include "components/signin/core/browser/test_signin_client.h"
@@ -33,6 +32,10 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_ANDROID)
+#include "components/signin/core/browser/child_account_info_fetcher_android.h"
+#endif
+
namespace {
// Simple wrapper around a static string; used to avoid implicit conversion
// of the account key to an std::string (which is the type used for account
@@ -74,7 +77,6 @@ const char kTokenInfoIncompleteResponseFormat[] =
enum TrackingEventType {
UPDATED,
- IMAGE_UPDATED,
REMOVED,
};
@@ -131,9 +133,6 @@ class TrackingEvent {
case UPDATED:
typestr = "UPD";
break;
- case IMAGE_UPDATED:
- typestr = "IMG_UPD";
- break;
case REMOVED:
typestr = "REM";
break;
@@ -181,8 +180,6 @@ class AccountTrackerObserver : public AccountTrackerService::Observer {
private:
// AccountTrackerService::Observer implementation
void OnAccountUpdated(const AccountInfo& ids) override;
- void OnAccountImageUpdated(const std::string& account_id,
- const gfx::Image& image) override;
void OnAccountRemoved(const AccountInfo& ids) override;
std::vector<TrackingEvent> events_;
@@ -192,12 +189,6 @@ void AccountTrackerObserver::OnAccountUpdated(const AccountInfo& ids) {
events_.push_back(TrackingEvent(UPDATED, ids.account_id, ids.gaia));
}
-void AccountTrackerObserver::OnAccountImageUpdated(
- const std::string& account_id,
- const gfx::Image& image) {
- events_.push_back(TrackingEvent(IMAGE_UPDATED, account_id, std::string()));
-}
-
void AccountTrackerObserver::OnAccountRemoved(const AccountInfo& ids) {
events_.push_back(TrackingEvent(REMOVED, ids.account_id, ids.gaia));
}
@@ -232,7 +223,9 @@ testing::AssertionResult AccountTrackerObserver::CheckEvents(
class AccountTrackerServiceTest : public testing::Test {
public:
AccountTrackerServiceTest() : signin_client_(&pref_service_) {
- ChildAccountInfoFetcher::InitializeForTests();
+#if defined(OS_ANDROID)
+ ChildAccountInfoFetcherAndroid::InitializeForTests();
+#endif
AccountTrackerService::RegisterPrefs(pref_service_.registry());
AccountFetcherService::RegisterPrefs(pref_service_.registry());
@@ -289,7 +282,7 @@ class AccountTrackerServiceTest : public testing::Test {
EXPECT_EQ(AccountKeyToAccountId(account_key), info.account_id);
EXPECT_EQ(AccountKeyToGaiaId(account_key), info.gaia);
EXPECT_EQ(AccountKeyToEmail(account_key), info.email);
- EXPECT_EQ(AccountTrackerService::kNoHostedDomainFound, info.hosted_domain);
+ EXPECT_EQ(kNoHostedDomainFound, info.hosted_domain);
EXPECT_EQ(AccountKeyToFullName(account_key), info.full_name);
EXPECT_EQ(AccountKeyToGivenName(account_key), info.given_name);
EXPECT_EQ(AccountKeyToLocale(account_key), info.locale);
@@ -469,16 +462,16 @@ TEST_F(AccountTrackerServiceTest, TokenAvailable_UserInfo_ImageSuccess) {
}));
EXPECT_TRUE(account_tracker()
- ->GetAccountImage(AccountKeyToAccountId(kAccountKeyAlpha))
- .IsEmpty());
+ ->GetAccountInfo(AccountKeyToAccountId(kAccountKeyAlpha))
+ .account_image.IsEmpty());
ReturnAccountImageFetchSuccess(kAccountKeyAlpha);
EXPECT_TRUE(observer()->CheckEvents({
- TrackingEvent(IMAGE_UPDATED, AccountKeyToAccountId(kAccountKeyAlpha),
+ TrackingEvent(UPDATED, AccountKeyToAccountId(kAccountKeyAlpha),
AccountKeyToGaiaId(kAccountKeyAlpha)),
}));
EXPECT_FALSE(account_tracker()
- ->GetAccountImage(AccountKeyToAccountId(kAccountKeyAlpha))
- .IsEmpty());
+ ->GetAccountInfo(AccountKeyToAccountId(kAccountKeyAlpha))
+ .account_image.IsEmpty());
}
TEST_F(AccountTrackerServiceTest, TokenAvailable_UserInfo_ImageFailure) {
@@ -491,12 +484,12 @@ TEST_F(AccountTrackerServiceTest, TokenAvailable_UserInfo_ImageFailure) {
}));
EXPECT_TRUE(account_tracker()
- ->GetAccountImage(AccountKeyToAccountId(kAccountKeyAlpha))
- .IsEmpty());
+ ->GetAccountInfo(AccountKeyToAccountId(kAccountKeyAlpha))
+ .account_image.IsEmpty());
ReturnAccountImageFetchFailure(kAccountKeyAlpha);
EXPECT_TRUE(account_tracker()
- ->GetAccountImage(AccountKeyToAccountId(kAccountKeyAlpha))
- .IsEmpty());
+ ->GetAccountInfo(AccountKeyToAccountId(kAccountKeyAlpha))
+ .account_image.IsEmpty());
}
TEST_F(AccountTrackerServiceTest, TokenAvailable_UserInfo_Revoked) {
@@ -697,9 +690,9 @@ TEST_F(AccountTrackerServiceTest, Persistence) {
// Wait until all account images are loaded.
scoped_task_environment_.RunUntilIdle();
EXPECT_TRUE(observer()->CheckEvents({
- TrackingEvent(IMAGE_UPDATED, AccountKeyToAccountId(kAccountKeyAlpha),
+ TrackingEvent(UPDATED, AccountKeyToAccountId(kAccountKeyAlpha),
AccountKeyToGaiaId(kAccountKeyAlpha)),
- TrackingEvent(IMAGE_UPDATED, AccountKeyToAccountId(kAccountKeyBeta),
+ TrackingEvent(UPDATED, AccountKeyToAccountId(kAccountKeyBeta),
AccountKeyToGaiaId(kAccountKeyBeta)),
}));
@@ -777,7 +770,7 @@ TEST_F(AccountTrackerServiceTest, SeedAccountInfoFull) {
// Validate that seeding new full informations to an existing account works
// and sends a notification.
info.given_name = AccountKeyToGivenName(kAccountKeyAlpha);
- info.hosted_domain = AccountTrackerService::kNoHostedDomainFound;
+ info.hosted_domain = kNoHostedDomainFound;
info.locale = AccountKeyToLocale(kAccountKeyAlpha);
info.picture_url = AccountKeyToPictureURL(kAccountKeyAlpha);
account_tracker()->SeedAccountInfo(info);
@@ -791,7 +784,7 @@ TEST_F(AccountTrackerServiceTest, SeedAccountInfoFull) {
// Validate that seeding invalid information to an existing account doesn't
// work and doesn't send a notification.
- info.given_name = AccountKeyToGivenName(kAccountKeyBeta);
+ info.given_name = std::string();
account_tracker()->SeedAccountInfo(info);
stored_info = account_tracker()->GetAccountInfo(info.account_id);
EXPECT_EQ(info.gaia, stored_info.gaia);
@@ -928,7 +921,7 @@ TEST_F(AccountTrackerServiceTest, NoDeprecatedServiceFlags) {
const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
- ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
+ ListPrefUpdate update(prefs(), prefs::kAccountInfo);
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("account_id", email_alpha);
@@ -947,7 +940,7 @@ TEST_F(AccountTrackerServiceTest, MigrateDeprecatedServiceFlags) {
const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
- ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
+ ListPrefUpdate update(prefs(), prefs::kAccountInfo);
std::unique_ptr<base::ListValue> service_flags(new base::ListValue());
service_flags->Append(std::make_unique<base::Value>("uca"));
@@ -975,7 +968,7 @@ TEST_F(AccountTrackerServiceTest, MigrateAccountIdToGaiaId) {
const std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
const std::string gaia_beta = AccountKeyToGaiaId(kAccountKeyBeta);
- ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
+ ListPrefUpdate update(prefs(), prefs::kAccountInfo);
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("account_id", email_alpha);
@@ -1019,7 +1012,7 @@ TEST_F(AccountTrackerServiceTest, CanNotMigrateAccountIdToGaiaId) {
const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
const std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
- ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
+ ListPrefUpdate update(prefs(), prefs::kAccountInfo);
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("account_id", email_alpha);
@@ -1063,7 +1056,7 @@ TEST_F(AccountTrackerServiceTest, GaiaIdMigrationCrashInTheMiddle) {
const std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
const std::string gaia_beta = AccountKeyToGaiaId(kAccountKeyBeta);
- ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
+ ListPrefUpdate update(prefs(), prefs::kAccountInfo);
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("account_id", email_alpha);
@@ -1340,7 +1333,7 @@ TEST_F(AccountTrackerServiceTest, CountOfLoadedAccounts_TwoAccounts) {
const std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
const std::string gaia_beta = AccountKeyToGaiaId(kAccountKeyBeta);
- ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
+ ListPrefUpdate update(prefs(), prefs::kAccountInfo);
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("account_id", email_alpha);
@@ -1368,7 +1361,7 @@ TEST_F(AccountTrackerServiceTest, CountOfLoadedAccounts_TwoAccountsOneInvalid) {
const std::string email_foobar = AccountKeyToEmail(kAccountKeyFooDotBar);
const std::string gaia_foobar = AccountKeyToGaiaId(kAccountKeyFooDotBar);
- ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
+ ListPrefUpdate update(prefs(), prefs::kAccountInfo);
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
dict->SetString("account_id", email_alpha);
diff --git a/chromium/components/signin/core/browser/android/BUILD.gn b/chromium/components/signin/core/browser/android/BUILD.gn
index 61fb92b96be..71bc6deee25 100644
--- a/chromium/components/signin/core/browser/android/BUILD.gn
+++ b/chromium/components/signin/core/browser/android/BUILD.gn
@@ -6,7 +6,9 @@ import("//build/config/android/rules.gni")
generate_jni("jni_headers") {
sources = [
+ "java/src/org/chromium/components/signin/AccountTrackerService.java",
"java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java",
+ "java/src/org/chromium/components/signin/OAuth2TokenService.java",
]
jni_package = "components/signin"
}
@@ -28,6 +30,7 @@ android_library("java") {
"java/src/org/chromium/components/signin/AccountManagerFacade.java",
"java/src/org/chromium/components/signin/AccountManagerResult.java",
"java/src/org/chromium/components/signin/AccountsChangeObserver.java",
+ "java/src/org/chromium/components/signin/AccountTrackerService.java",
"java/src/org/chromium/components/signin/AuthException.java",
"java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java",
"java/src/org/chromium/components/signin/ChildAccountStatus.java",
@@ -35,6 +38,7 @@ android_library("java") {
"java/src/org/chromium/components/signin/GmsAvailabilityException.java",
"java/src/org/chromium/components/signin/GmsJustUpdatedException.java",
"java/src/org/chromium/components/signin/util/PatternMatcher.java",
+ "java/src/org/chromium/components/signin/OAuth2TokenService.java",
"java/src/org/chromium/components/signin/ProfileDataSource.java",
"java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java",
]
@@ -87,5 +91,6 @@ android_library("signin_java_test_support") {
java_files = [
"javatests/src/org/chromium/components/signin/test/util/AccountHolder.java",
"javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java",
+ "javatests/src/org/chromium/components/signin/test/util/FakeProfileDataSource.java",
]
}
diff --git a/chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java b/chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
index 5f4cc8dd9bd..3feda0e0544 100644
--- a/chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
+++ b/chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
@@ -20,6 +20,7 @@ import android.os.UserManager;
import android.support.annotation.AnyThread;
import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
import org.chromium.base.Callback;
import org.chromium.base.ContextUtils;
@@ -30,7 +31,6 @@ import org.chromium.base.VisibleForTesting;
import org.chromium.base.metrics.CachedMetrics;
import org.chromium.base.task.AsyncTask;
import org.chromium.components.signin.util.PatternMatcher;
-import org.chromium.net.NetworkChangeNotifier;
import java.util.ArrayList;
import java.util.Arrays;
@@ -39,8 +39,6 @@ import java.util.List;
import java.util.Locale;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;
@@ -100,26 +98,6 @@ public class AccountManagerFacade {
private final ArrayList<Runnable> mCallbacksWaitingForPendingUpdates = new ArrayList<>();
/**
- * A simple callback for getAuthToken.
- */
- public interface GetAuthTokenCallback {
- /**
- * Invoked on the UI thread if a token is provided by the AccountManager.
- *
- * @param token Auth token, guaranteed not to be null.
- */
- void tokenAvailable(String token);
-
- /**
- * Invoked on the UI thread if no token is available.
- *
- * @param isTransientError Indicates if the error is transient (network timeout or
- * unavailable, etc) or persistent (bad credentials, permission denied, etc).
- */
- void tokenUnavailable(boolean isTransientError);
- }
-
- /**
* @param delegate the AccountManagerDelegate to use as a backend
*/
private AccountManagerFacade(AccountManagerDelegate delegate) {
@@ -451,64 +429,30 @@ public class AccountManagerFacade {
}
/**
- * Gets the auth token and returns the response asynchronously.
- * This should be called when we have a foreground activity that needs an auth token.
- * If encountered an IO error, it will attempt to retry when the network is back.
- *
- * - Assumes that the account is a valid account.
+ * Synchronously gets an OAuth2 access token. May return a cached version, use
+ * {@link #invalidateAccessToken} to invalidate a token in the cache.
+ * @param account The {@link Account} for which the token is requested.
+ * @param scope OAuth2 scope for which the requested token should be valid.
+ * @return The OAuth2 access token as a string.
*/
- @MainThread
- public void getAuthToken(final Account account, final String authTokenType,
- final GetAuthTokenCallback callback) {
- ConnectionRetry.runAuthTask(new AuthTask<String>() {
- @Override
- public String run() throws AuthException {
- return mDelegate.getAuthToken(account, authTokenType);
- }
- @Override
- public void onSuccess(String token) {
- callback.tokenAvailable(token);
- }
- @Override
- public void onFailure(boolean isTransientError) {
- callback.tokenUnavailable(isTransientError);
- }
- });
- }
-
- /**
- * Invalidates the old token (if non-null/non-empty) and asynchronously generates a new one.
- *
- * - Assumes that the account is a valid account.
- */
- @MainThread
- public void getNewAuthToken(Account account, String authToken, String authTokenType,
- GetAuthTokenCallback callback) {
- invalidateAuthToken(authToken);
- getAuthToken(account, authTokenType, callback);
+ @WorkerThread
+ String getAccessToken(Account account, String scope) throws AuthException {
+ assert account != null;
+ assert scope != null;
+ // TODO(bsazonov): Rename delegate's getAuthToken to getAccessToken.
+ return mDelegate.getAuthToken(account, scope);
}
/**
- * Clear an auth token from the local cache with respect to the ApplicationContext.
+ * Synchronously clears an OAuth2 access token from the cache. Use {@link #getAccessToken}
+ * to issue a new token after invalidating the old one.
+ * @param accessToken The access token to invalidate.
*/
- @MainThread
- public void invalidateAuthToken(final String authToken) {
- if (authToken == null || authToken.isEmpty()) {
- return;
- }
- ConnectionRetry.runAuthTask(new AuthTask<Boolean>() {
- @Override
- public Boolean run() throws AuthException {
- mDelegate.invalidateAuthToken(authToken);
- return true;
- }
- @Override
- public void onSuccess(Boolean result) {}
- @Override
- public void onFailure(boolean isTransientError) {
- Log.e(TAG, "Failed to invalidate auth token: " + authToken);
- }
- });
+ @WorkerThread
+ void invalidateAccessToken(String accessToken) throws AuthException {
+ assert accessToken != null;
+ // TODO(bsazonov): Rename delegate's invalidateAuthToken to invalidateAccessToken.
+ mDelegate.invalidateAuthToken(accessToken);
}
// Incorrectly infers that this is called on a worker thread because of AsyncTask doInBackground
@@ -763,83 +707,4 @@ public class AccountManagerFacade {
decrementUpdateCounter();
}
}
-
- private interface AuthTask<T> {
- T run() throws AuthException;
- void onSuccess(T result);
- void onFailure(boolean isTransientError);
- }
-
- /**
- * A helper class to encapsulate network connection retry logic for AuthTasks.
- *
- * The task will be run on the background thread. If it encounters a transient error, it will
- * wait for a network change and retry up to MAX_TRIES times.
- */
- private static class ConnectionRetry<T>
- implements NetworkChangeNotifier.ConnectionTypeObserver {
- private static final int MAX_TRIES = 3;
-
- private final AuthTask<T> mAuthTask;
- private final AtomicInteger mNumTries;
- private final AtomicBoolean mIsTransientError;
-
- public static <T> void runAuthTask(AuthTask<T> authTask) {
- new ConnectionRetry<>(authTask).attempt();
- }
-
- private ConnectionRetry(AuthTask<T> authTask) {
- mAuthTask = authTask;
- mNumTries = new AtomicInteger(0);
- mIsTransientError = new AtomicBoolean(false);
- }
-
- /**
- * Tries running the {@link AuthTask} in the background. This object is never registered
- * as a {@link NetworkChangeNotifier.ConnectionTypeObserver} when this method is called.
- */
- private void attempt() {
- ThreadUtils.assertOnUiThread();
- // Clear any transient error.
- mIsTransientError.set(false);
- new AsyncTask<T>() {
- @Override
- public T doInBackground() {
- try {
- return mAuthTask.run();
- } catch (AuthException ex) {
- Log.w(TAG, "Failed to perform auth task: %s", ex.stringifyCausalChain());
- Log.d(TAG, "Exception details:", ex);
- mIsTransientError.set(ex.isTransientError());
- }
- return null;
- }
- @Override
- public void onPostExecute(T result) {
- if (result != null) {
- mAuthTask.onSuccess(result);
- } else if (!mIsTransientError.get() || mNumTries.incrementAndGet() >= MAX_TRIES
- || !NetworkChangeNotifier.isInitialized()) {
- // Permanent error, ran out of tries, or we can't listen for network
- // change events; give up.
- mAuthTask.onFailure(mIsTransientError.get());
- } else {
- // Transient error with tries left; register for another attempt.
- NetworkChangeNotifier.addConnectionTypeObserver(ConnectionRetry.this);
- }
- }
- }
- .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- @Override
- public void onConnectionTypeChanged(int connectionType) {
- assert mNumTries.get() < MAX_TRIES;
- if (NetworkChangeNotifier.isOnline()) {
- // The network is back; stop listening and try again.
- NetworkChangeNotifier.removeConnectionTypeObserver(this);
- attempt();
- }
- }
- }
}
diff --git a/chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountTrackerService.java b/chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountTrackerService.java
new file mode 100644
index 00000000000..a431cc2dbde
--- /dev/null
+++ b/chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountTrackerService.java
@@ -0,0 +1,253 @@
+// Copyright 2015 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.
+
+package org.chromium.components.signin;
+
+import android.os.SystemClock;
+import android.support.annotation.IntDef;
+
+import org.chromium.base.Log;
+import org.chromium.base.ObserverList;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.task.AsyncTask;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Android wrapper of AccountTrackerService which provides access from the java layer.
+ * It offers the capability of fetching and seeding system accounts into AccountTrackerService in
+ * C++ layer, and notifies observers when it is complete.
+ */
+public class AccountTrackerService {
+ private static final String TAG = "AccountService";
+
+ private final long mNativeAccountTrackerService;
+ private @SystemAccountsSeedingStatus int mSystemAccountsSeedingStatus;
+ private boolean mSystemAccountsChanged;
+ private boolean mSyncForceRefreshedForTest;
+ private AccountsChangeObserver mAccountsChangeObserver;
+
+ @IntDef({SystemAccountsSeedingStatus.SEEDING_NOT_STARTED,
+ SystemAccountsSeedingStatus.SEEDING_IN_PROGRESS,
+ SystemAccountsSeedingStatus.SEEDING_DONE,
+ SystemAccountsSeedingStatus.SEEDING_VALIDATING})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SystemAccountsSeedingStatus {
+ int SEEDING_NOT_STARTED = 0;
+ int SEEDING_IN_PROGRESS = 1;
+ int SEEDING_DONE = 2;
+ int SEEDING_VALIDATING = 3;
+ }
+
+ /**
+ * Classes that want to listen for system accounts fetching and seeding should implement
+ * this interface and register with {@link #addSystemAccountsSeededListener}.
+ */
+ public interface OnSystemAccountsSeededListener {
+ // Called at the end of seedSystemAccounts().
+ void onSystemAccountsSeedingComplete();
+ // Called in invalidateAccountSeedStatus() indicating that accounts have changed.
+ void onSystemAccountsChanged();
+ }
+
+ private final ObserverList<OnSystemAccountsSeededListener> mSystemAccountsSeedingObservers =
+ new ObserverList<>();
+
+ private AccountTrackerService(long nativeAccountTrackerService) {
+ mNativeAccountTrackerService = nativeAccountTrackerService;
+ mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_NOT_STARTED;
+ mSystemAccountsChanged = false;
+ }
+
+ @CalledByNative
+ private static AccountTrackerService create(long nativeAccountTrackerService) {
+ ThreadUtils.assertOnUiThread();
+ return new AccountTrackerService(nativeAccountTrackerService);
+ }
+
+ /**
+ * Checks whether the account id <-> email mapping has been seeded into C++ layer.
+ * If not, it automatically starts fetching the mapping and seeds it.
+ * @return Whether the accounts have been seeded already.
+ */
+ public boolean checkAndSeedSystemAccounts() {
+ ThreadUtils.assertOnUiThread();
+ if (mSystemAccountsSeedingStatus == SystemAccountsSeedingStatus.SEEDING_DONE
+ && !mSystemAccountsChanged) {
+ return true;
+ }
+ if ((mSystemAccountsSeedingStatus == SystemAccountsSeedingStatus.SEEDING_NOT_STARTED
+ || mSystemAccountsChanged)
+ && mSystemAccountsSeedingStatus
+ != SystemAccountsSeedingStatus.SEEDING_IN_PROGRESS) {
+ seedSystemAccounts();
+ }
+ return false;
+ }
+
+ /**
+ * Register an |observer| to observe system accounts seeding status.
+ */
+ public void addSystemAccountsSeededListener(OnSystemAccountsSeededListener observer) {
+ ThreadUtils.assertOnUiThread();
+ mSystemAccountsSeedingObservers.addObserver(observer);
+ if (mSystemAccountsSeedingStatus == SystemAccountsSeedingStatus.SEEDING_DONE) {
+ observer.onSystemAccountsSeedingComplete();
+ }
+ }
+
+ /**
+ * Remove an |observer| from the list of observers.
+ */
+ public void removeSystemAccountsSeededListener(OnSystemAccountsSeededListener observer) {
+ ThreadUtils.assertOnUiThread();
+ mSystemAccountsSeedingObservers.removeObserver(observer);
+ }
+
+ private void seedSystemAccounts() {
+ ThreadUtils.assertOnUiThread();
+ mSystemAccountsChanged = false;
+ mSyncForceRefreshedForTest = false;
+
+ final AccountIdProvider accountIdProvider = AccountIdProvider.getInstance();
+ if (accountIdProvider.canBeUsed()) {
+ mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_IN_PROGRESS;
+ } else {
+ mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_NOT_STARTED;
+ return;
+ }
+
+ if (mAccountsChangeObserver == null) {
+ mAccountsChangeObserver =
+ () -> invalidateAccountSeedStatus(false /* don't reseed right now */);
+ AccountManagerFacade.get().addObserver(mAccountsChangeObserver);
+ }
+
+ AccountManagerFacade.get().tryGetGoogleAccounts(accounts -> {
+ new AsyncTask<String[][]>() {
+ @Override
+ public String[][] doInBackground() {
+ Log.d(TAG, "Getting id/email mapping");
+
+ long seedingStartTime = SystemClock.elapsedRealtime();
+
+ String[][] accountIdNameMap = new String[2][accounts.size()];
+ for (int i = 0; i < accounts.size(); ++i) {
+ accountIdNameMap[0][i] =
+ accountIdProvider.getAccountId(accounts.get(i).name);
+ accountIdNameMap[1][i] = accounts.get(i).name;
+ }
+
+ RecordHistogram.recordTimesHistogram("Signin.AndroidGetAccountIdsTime",
+ SystemClock.elapsedRealtime() - seedingStartTime,
+ TimeUnit.MILLISECONDS);
+
+ return accountIdNameMap;
+ }
+ @Override
+ public void onPostExecute(String[][] accountIdNameMap) {
+ if (mSyncForceRefreshedForTest) return;
+ if (mSystemAccountsChanged) {
+ seedSystemAccounts();
+ return;
+ }
+ if (areAccountIdsValid(accountIdNameMap[0])) {
+ nativeSeedAccountsInfo(mNativeAccountTrackerService, accountIdNameMap[0],
+ accountIdNameMap[1]);
+ mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_DONE;
+ notifyObserversOnSeedingComplete();
+ } else {
+ Log.w(TAG, "Invalid mapping of id/email");
+ seedSystemAccounts();
+ }
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ });
+ }
+
+ private boolean areAccountIdsValid(String[] accountIds) {
+ for (String accountId : accountIds) {
+ if (accountId == null) return false;
+ }
+ return true;
+ }
+
+ private void notifyObserversOnSeedingComplete() {
+ for (OnSystemAccountsSeededListener observer : mSystemAccountsSeedingObservers) {
+ observer.onSystemAccountsSeedingComplete();
+ }
+ }
+
+ /**
+ * Seed system accounts into AccountTrackerService synchronously for test purpose.
+ */
+ @VisibleForTesting
+ public void syncForceRefreshForTest(String[] accountIds, String[] accountNames) {
+ ThreadUtils.assertOnUiThread();
+ mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_IN_PROGRESS;
+ mSystemAccountsChanged = false;
+ mSyncForceRefreshedForTest = true;
+ nativeSeedAccountsInfo(mNativeAccountTrackerService, accountIds, accountNames);
+ mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_DONE;
+ }
+
+ /**
+ * Notifies the AccountTrackerService about changed system accounts. without actually triggering
+ * @param reSeedAccounts Whether to also start seeding the new account information immediately.
+ */
+ public void invalidateAccountSeedStatus(boolean reSeedAccounts) {
+ ThreadUtils.assertOnUiThread();
+ mSystemAccountsChanged = true;
+ notifyObserversOnAccountsChange();
+ if (reSeedAccounts) checkAndSeedSystemAccounts();
+ }
+
+ /**
+ * Verifies whether seeded accounts in AccountTrackerService are up-to-date with the accounts in
+ * Android. It sets seeding status to SEEDING_VALIDATING temporarily to block services depending
+ * on it and sets it back to SEEDING_DONE after passing the verification. This function is
+ * created because accounts changed notification from Android to Chrome has latency.
+ */
+ public void validateSystemAccounts() {
+ ThreadUtils.assertOnUiThread();
+ if (!checkAndSeedSystemAccounts()) {
+ // Do nothing if seeding is not done.
+ return;
+ }
+
+ mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_VALIDATING;
+ AccountManagerFacade.get().tryGetGoogleAccounts(accounts -> {
+ if (mSystemAccountsChanged
+ || mSystemAccountsSeedingStatus
+ != SystemAccountsSeedingStatus.SEEDING_VALIDATING) {
+ return;
+ }
+
+ String[] accountNames = new String[accounts.size()];
+ for (int i = 0; i < accounts.size(); ++i) {
+ accountNames[i] = accounts.get(i).name;
+ }
+ if (nativeAreAccountsSeeded(mNativeAccountTrackerService, accountNames)) {
+ mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_DONE;
+ notifyObserversOnSeedingComplete();
+ }
+ });
+ }
+
+ private void notifyObserversOnAccountsChange() {
+ for (OnSystemAccountsSeededListener observer : mSystemAccountsSeedingObservers) {
+ observer.onSystemAccountsChanged();
+ }
+ }
+
+ private static native void nativeSeedAccountsInfo(
+ long accountTrackerServicePtr, String[] gaiaIds, String[] accountNames);
+ private static native boolean nativeAreAccountsSeeded(
+ long accountTrackerServicePtr, String[] accountNames);
+}
diff --git a/chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/OAuth2TokenService.java b/chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/OAuth2TokenService.java
new file mode 100644
index 00000000000..c1f25744a9f
--- /dev/null
+++ b/chromium/components/signin/core/browser/android/java/src/org/chromium/components/signin/OAuth2TokenService.java
@@ -0,0 +1,500 @@
+// Copyright 2013 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.
+
+package org.chromium.components.signin;
+
+import android.accounts.Account;
+import android.support.annotation.MainThread;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.Log;
+import org.chromium.base.ObserverList;
+import org.chromium.base.StrictModeContext;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.task.AsyncTask;
+import org.chromium.net.NetworkChangeNotifier;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Java instance for the native OAuth2TokenService.
+ * <p/>
+ * This class forwards calls to request or invalidate access tokens made by native code to
+ * AccountManagerFacade and forwards callbacks to native code.
+ * <p/>
+ */
+public final class OAuth2TokenService
+ implements AccountTrackerService.OnSystemAccountsSeededListener {
+ private static final String TAG = "OAuth2TokenService";
+
+ @VisibleForTesting
+ public static final String STORED_ACCOUNTS_KEY = "google.services.stored_accounts";
+
+ /**
+ * A simple callback for getAccessToken.
+ */
+ public interface GetAccessTokenCallback {
+ /**
+ * Invoked on the UI thread if a token is provided by the AccountManager.
+ *
+ * @param token Access token, guaranteed not to be null.
+ */
+ void onGetTokenSuccess(String token);
+
+ /**
+ * Invoked on the UI thread if no token is available.
+ *
+ * @param isTransientError Indicates if the error is transient (network timeout or
+ * unavailable, etc) or persistent (bad credentials, permission denied, etc).
+ */
+ void onGetTokenFailure(boolean isTransientError);
+ }
+
+ /**
+ * Classes that want to listen for refresh token availability should
+ * implement this interface and register with {@link #addObserver}.
+ */
+ public interface OAuth2TokenServiceObserver {
+ void onRefreshTokenAvailable(Account account);
+ void onRefreshTokenRevoked(Account account);
+ void onRefreshTokensLoaded();
+ }
+
+ private static final String OAUTH2_SCOPE_PREFIX = "oauth2:";
+
+ private final long mNativeOAuth2TokenServiceDelegate;
+ private final AccountTrackerService mAccountTrackerService;
+ private final ObserverList<OAuth2TokenServiceObserver> mObservers = new ObserverList<>();
+
+ private boolean mPendingValidation;
+ private boolean mPendingValidationForceNotifications;
+
+ private OAuth2TokenService(
+ long nativeOAuth2TokenServiceDelegate, AccountTrackerService accountTrackerService) {
+ mNativeOAuth2TokenServiceDelegate = nativeOAuth2TokenServiceDelegate;
+ mAccountTrackerService = accountTrackerService;
+
+ mAccountTrackerService.addSystemAccountsSeededListener(this);
+ }
+
+ @CalledByNative
+ private static OAuth2TokenService create(
+ long nativeOAuth2TokenServiceDelegate, AccountTrackerService accountTrackerService) {
+ ThreadUtils.assertOnUiThread();
+ return new OAuth2TokenService(nativeOAuth2TokenServiceDelegate, accountTrackerService);
+ }
+
+ @VisibleForTesting
+ public void addObserver(OAuth2TokenServiceObserver observer) {
+ ThreadUtils.assertOnUiThread();
+ mObservers.addObserver(observer);
+ }
+
+ @VisibleForTesting
+ public void removeObserver(OAuth2TokenServiceObserver observer) {
+ ThreadUtils.assertOnUiThread();
+ mObservers.removeObserver(observer);
+ }
+
+ private static Account getAccountOrNullFromUsername(String username) {
+ if (username == null) {
+ Log.e(TAG, "Username is null");
+ return null;
+ }
+
+ AccountManagerFacade accountManagerFacade = AccountManagerFacade.get();
+ Account account = accountManagerFacade.getAccountFromName(username);
+ if (account == null) {
+ Log.e(TAG, "Account not found for provided username.");
+ return null;
+ }
+ return account;
+ }
+
+ /**
+ * Called by native to list the active account names in the OS.
+ */
+ @VisibleForTesting
+ @CalledByNative
+ public static String[] getSystemAccountNames() {
+ // TODO(https://crbug.com/768366): Remove this after adding cache to account manager facade.
+ // This function is called by native code on UI thread.
+ try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+ List<String> accountNames = AccountManagerFacade.get().tryGetGoogleAccountNames();
+ return accountNames.toArray(new String[accountNames.size()]);
+ }
+ }
+
+ /**
+ * Called by native to list the accounts Id with OAuth2 refresh tokens.
+ * This can differ from getSystemAccountNames as the user add/remove accounts
+ * from the OS. validateAccounts should be called to keep these two
+ * in sync.
+ */
+ @CalledByNative
+ public static String[] getAccounts() {
+ return getStoredAccounts();
+ }
+
+ /**
+ * Called by native to retrieve OAuth2 tokens.
+ * @param username The native username (email address).
+ * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix).
+ * @param nativeCallback The pointer to the native callback that should be run upon completion.
+ */
+ @MainThread
+ @CalledByNative
+ private static void getAccessTokenFromNative(
+ String username, String scope, final long nativeCallback) {
+ Account account = getAccountOrNullFromUsername(username);
+ if (account == null) {
+ ThreadUtils.postOnUiThread(() -> nativeOAuth2TokenFetched(null, false, nativeCallback));
+ return;
+ }
+ String oauth2Scope = OAUTH2_SCOPE_PREFIX + scope;
+ getAccessToken(account, oauth2Scope, new GetAccessTokenCallback() {
+ @Override
+ public void onGetTokenSuccess(String token) {
+ nativeOAuth2TokenFetched(token, false, nativeCallback);
+ }
+
+ @Override
+ public void onGetTokenFailure(boolean isTransientError) {
+ nativeOAuth2TokenFetched(null, isTransientError, nativeCallback);
+ }
+ });
+ }
+
+ /**
+ * Call this method to retrieve an OAuth2 access token for the given account and scope. Please
+ * note that this method expects a scope with 'oauth2:' prefix.
+ * @param account the account to get the access token for.
+ * @param scope The scope to get an auth token for (with Android-style 'oauth2:' prefix).
+ * @param callback called on successful and unsuccessful fetching of auth token.
+ */
+ @MainThread
+ public static void getAccessToken(
+ Account account, String scope, GetAccessTokenCallback callback) {
+ ConnectionRetry.runAuthTask(new AuthTask<String>() {
+ @Override
+ public String run() throws AuthException {
+ return AccountManagerFacade.get().getAccessToken(account, scope);
+ }
+ @Override
+ public void onSuccess(String token) {
+ callback.onGetTokenSuccess(token);
+ }
+ @Override
+ public void onFailure(boolean isTransientError) {
+ callback.onGetTokenFailure(isTransientError);
+ }
+ });
+ }
+
+ /**
+ * Called by native to invalidate an OAuth2 token. Please note that the token is invalidated
+ * asynchronously.
+ */
+ @MainThread
+ @CalledByNative
+ public static void invalidateAccessToken(String accessToken) {
+ if (TextUtils.isEmpty(accessToken)) {
+ return;
+ }
+ ConnectionRetry.runAuthTask(new AuthTask<Boolean>() {
+ @Override
+ public Boolean run() throws AuthException {
+ AccountManagerFacade.get().invalidateAccessToken(accessToken);
+ return true;
+ }
+ @Override
+ public void onSuccess(Boolean result) {}
+ @Override
+ public void onFailure(boolean isTransientError) {
+ Log.e(TAG, "Failed to invalidate auth token: " + accessToken);
+ }
+ });
+ }
+
+ /**
+ * Invalidates the old token (if non-null/non-empty) and asynchronously generates a new one.
+ * @param account the account to get the access token for.
+ * @param oldToken The old token to be invalidated or null.
+ * @param scope The scope to get an auth token for (with Android-style 'oauth2:' prefix).
+ * @param callback called on successful and unsuccessful fetching of auth token.
+ */
+ public static void getNewAccessToken(Account account, @Nullable String oldToken, String scope,
+ GetAccessTokenCallback callback) {
+ ConnectionRetry.runAuthTask(new AuthTask<String>() {
+ @Override
+ public String run() throws AuthException {
+ if (!TextUtils.isEmpty(oldToken)) {
+ AccountManagerFacade.get().invalidateAccessToken(oldToken);
+ }
+ return AccountManagerFacade.get().getAccessToken(account, scope);
+ }
+ @Override
+ public void onSuccess(String token) {
+ callback.onGetTokenSuccess(token);
+ }
+ @Override
+ public void onFailure(boolean isTransientError) {
+ callback.onGetTokenFailure(isTransientError);
+ }
+ });
+ }
+
+ /**
+ * Call this method to retrieve an OAuth2 access token for the given account and scope. This
+ * method times out after the specified timeout, and will return null if that happens.
+ *
+ * Given that this is a blocking method call, this should never be called from the UI thread.
+ *
+ * @param account the account to get the access token for.
+ * @param scope The scope to get an auth token for (without Android-style 'oauth2:' prefix).
+ * @param timeout the timeout.
+ * @param unit the unit for |timeout|.
+ */
+ @VisibleForTesting
+ public static String getAccessTokenWithTimeout(
+ Account account, String scope, long timeout, TimeUnit unit) {
+ assert !ThreadUtils.runningOnUiThread();
+ final AtomicReference<String> result = new AtomicReference<>();
+ final Semaphore semaphore = new Semaphore(0);
+ getAccessToken(account, scope, new GetAccessTokenCallback() {
+ @Override
+ public void onGetTokenSuccess(String token) {
+ result.set(token);
+ semaphore.release();
+ }
+
+ @Override
+ public void onGetTokenFailure(boolean isTransientError) {
+ result.set(null);
+ semaphore.release();
+ }
+ });
+ try {
+ if (semaphore.tryAcquire(timeout, unit)) {
+ return result.get();
+ } else {
+ Log.d(TAG, "Failed to retrieve auth token within timeout (%s %s)", timeout, unit);
+ return null;
+ }
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Got interrupted while waiting for auth token");
+ return null;
+ }
+ }
+
+ /**
+ * Called by native to check whether the account has an OAuth2 refresh token.
+ */
+ @CalledByNative
+ public static boolean hasOAuth2RefreshToken(String accountName) {
+ if (!AccountManagerFacade.get().isCachePopulated()) {
+ return false;
+ }
+
+ // Temporarily allowing disk read while fixing. TODO: http://crbug.com/618096.
+ // This function is called in RefreshTokenIsAvailable of OAuth2TokenService which is
+ // expected to be called in the UI thread synchronously.
+ try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+ return AccountManagerFacade.get().hasAccountForName(accountName);
+ }
+ }
+
+ /**
+ * Continue pending accounts validation after system accounts have been seeded into
+ * AccountTrackerService.
+ */
+ @Override
+ public void onSystemAccountsSeedingComplete() {
+ if (mPendingValidation) {
+ validateAccountsWithSignedInAccountName(mPendingValidationForceNotifications);
+ mPendingValidation = false;
+ mPendingValidationForceNotifications = false;
+ }
+ }
+
+ /**
+ * Clear pending accounts validation when system accounts in AccountTrackerService were
+ * refreshed.
+ */
+ @Override
+ public void onSystemAccountsChanged() {
+ mPendingValidationForceNotifications = false;
+ }
+
+ @CalledByNative
+ public void validateAccounts(boolean forceNotifications) {
+ ThreadUtils.assertOnUiThread();
+ if (!mAccountTrackerService.checkAndSeedSystemAccounts()) {
+ mPendingValidation = true;
+ mPendingValidationForceNotifications = forceNotifications;
+ return;
+ }
+
+ validateAccountsWithSignedInAccountName(forceNotifications);
+ }
+
+ private void validateAccountsWithSignedInAccountName(boolean forceNotifications) {
+ String currentlySignedInAccount = ChromeSigninController.get().getSignedInAccountName();
+ if (currentlySignedInAccount != null
+ && isSignedInAccountChanged(currentlySignedInAccount)) {
+ // Set currentlySignedInAccount to null for validation if signed-in account was changed
+ // (renamed or removed from the device), this will cause all credentials in token
+ // service be revoked.
+ // Could only get here during Chrome cold startup.
+ // After chrome started, SigninHelper and AccountsChangedReceiver will handle account
+ // change (re-signin or sign out signed-in account).
+ currentlySignedInAccount = null;
+ }
+ nativeValidateAccounts(
+ mNativeOAuth2TokenServiceDelegate, currentlySignedInAccount, forceNotifications);
+ }
+
+ private boolean isSignedInAccountChanged(String signedInAccountName) {
+ String[] accountNames = getSystemAccountNames();
+ for (String accountName : accountNames) {
+ if (accountName.equals(signedInAccountName)) return false;
+ }
+ return true;
+ }
+
+ @CalledByNative
+ private void notifyRefreshTokenAvailable(String accountName) {
+ assert accountName != null;
+ Account account = AccountManagerFacade.createAccountFromName(accountName);
+ for (OAuth2TokenServiceObserver observer : mObservers) {
+ observer.onRefreshTokenAvailable(account);
+ }
+ }
+
+ @CalledByNative
+ public void notifyRefreshTokenRevoked(String accountName) {
+ assert accountName != null;
+ Account account = AccountManagerFacade.createAccountFromName(accountName);
+ for (OAuth2TokenServiceObserver observer : mObservers) {
+ observer.onRefreshTokenRevoked(account);
+ }
+ }
+
+ @CalledByNative
+ public void notifyRefreshTokensLoaded() {
+ for (OAuth2TokenServiceObserver observer : mObservers) {
+ observer.onRefreshTokensLoaded();
+ }
+ }
+
+ private static String[] getStoredAccounts() {
+ Set<String> accounts =
+ ContextUtils.getAppSharedPreferences().getStringSet(STORED_ACCOUNTS_KEY, null);
+ return accounts == null ? new String[] {} : accounts.toArray(new String[0]);
+ }
+
+ @CalledByNative
+ private static void saveStoredAccounts(String[] accounts) {
+ Set<String> set = new HashSet<>(Arrays.asList(accounts));
+ ContextUtils.getAppSharedPreferences()
+ .edit()
+ .putStringSet(STORED_ACCOUNTS_KEY, set)
+ .apply();
+ }
+
+ private interface AuthTask<T> {
+ T run() throws AuthException;
+ void onSuccess(T result);
+ void onFailure(boolean isTransientError);
+ }
+
+ /**
+ * A helper class to encapsulate network connection retry logic for AuthTasks.
+ *
+ * The task will be run on the background thread. If it encounters a transient error, it will
+ * wait for a network change and retry up to MAX_TRIES times.
+ */
+ private static class ConnectionRetry<T>
+ implements NetworkChangeNotifier.ConnectionTypeObserver {
+ private static final int MAX_TRIES = 3;
+
+ private final AuthTask<T> mAuthTask;
+ private final AtomicInteger mNumTries;
+ private final AtomicBoolean mIsTransientError;
+
+ public static <T> void runAuthTask(AuthTask<T> authTask) {
+ new ConnectionRetry<>(authTask).attempt();
+ }
+
+ private ConnectionRetry(AuthTask<T> authTask) {
+ mAuthTask = authTask;
+ mNumTries = new AtomicInteger(0);
+ mIsTransientError = new AtomicBoolean(false);
+ }
+
+ /**
+ * Tries running the {@link AuthTask} in the background. This object is never registered
+ * as a {@link NetworkChangeNotifier.ConnectionTypeObserver} when this method is called.
+ */
+ private void attempt() {
+ ThreadUtils.assertOnUiThread();
+ // Clear any transient error.
+ mIsTransientError.set(false);
+ new AsyncTask<T>() {
+ @Override
+ public T doInBackground() {
+ try {
+ return mAuthTask.run();
+ } catch (AuthException ex) {
+ Log.w(TAG, "Failed to perform auth task: %s", ex.stringifyCausalChain());
+ Log.d(TAG, "Exception details:", ex);
+ mIsTransientError.set(ex.isTransientError());
+ }
+ return null;
+ }
+ @Override
+ public void onPostExecute(T result) {
+ if (result != null) {
+ mAuthTask.onSuccess(result);
+ } else if (!mIsTransientError.get() || mNumTries.incrementAndGet() >= MAX_TRIES
+ || !NetworkChangeNotifier.isInitialized()) {
+ // Permanent error, ran out of tries, or we can't listen for network
+ // change events; give up.
+ mAuthTask.onFailure(mIsTransientError.get());
+ } else {
+ // Transient error with tries left; register for another attempt.
+ NetworkChangeNotifier.addConnectionTypeObserver(ConnectionRetry.this);
+ }
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ @Override
+ public void onConnectionTypeChanged(int connectionType) {
+ assert mNumTries.get() < MAX_TRIES;
+ if (NetworkChangeNotifier.isOnline()) {
+ // The network is back; stop listening and try again.
+ NetworkChangeNotifier.removeConnectionTypeObserver(this);
+ attempt();
+ }
+ }
+ }
+
+ private static native void nativeOAuth2TokenFetched(
+ String authToken, boolean isTransientError, long nativeCallback);
+ private native void nativeValidateAccounts(long nativeOAuth2TokenServiceDelegateAndroid,
+ String currentlySignedInAccount, boolean forceNotifications);
+}
diff --git a/chromium/components/signin/core/browser/child_account_info_fetcher.cc b/chromium/components/signin/core/browser/child_account_info_fetcher.cc
deleted file mode 100644
index bc8e2670c78..00000000000
--- a/chromium/components/signin/core/browser/child_account_info_fetcher.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2015 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 "components/signin/core/browser/child_account_info_fetcher.h"
-
-#include "build/build_config.h"
-
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#if defined(OS_ANDROID)
-#include "components/signin/core/browser/child_account_info_fetcher_android.h"
-#else
-#include "components/signin/core/browser/child_account_info_fetcher_impl.h"
-#endif
-
-// static
-std::unique_ptr<ChildAccountInfoFetcher> ChildAccountInfoFetcher::CreateFrom(
- const std::string& account_id,
- AccountFetcherService* fetcher_service,
- OAuth2TokenService* token_service,
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- invalidation::InvalidationService* invalidation_service) {
-#if defined(OS_ANDROID)
- return ChildAccountInfoFetcherAndroid::Create(fetcher_service, account_id);
-#else
- return std::make_unique<ChildAccountInfoFetcherImpl>(
- account_id, fetcher_service, token_service, url_loader_factory,
- invalidation_service);
-#endif
-}
-
-ChildAccountInfoFetcher::~ChildAccountInfoFetcher() {
-}
-
-void ChildAccountInfoFetcher::InitializeForTests() {
-#if defined(OS_ANDROID)
- ChildAccountInfoFetcherAndroid::InitializeForTests();
-#endif
-}
diff --git a/chromium/components/signin/core/browser/child_account_info_fetcher.h b/chromium/components/signin/core/browser/child_account_info_fetcher.h
deleted file mode 100644
index f5891f5c97f..00000000000
--- a/chromium/components/signin/core/browser/child_account_info_fetcher.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2015 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 COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_H_
-#define COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_H_
-
-#include <memory>
-#include <string>
-
-#include "base/memory/ref_counted.h"
-#include "build/build_config.h"
-
-#if defined(OS_ANDROID)
-#include <jni.h>
-#endif
-
-namespace invalidation {
-class InvalidationService;
-}
-namespace network {
-class SharedURLLoaderFactory;
-}
-class AccountFetcherService;
-class OAuth2TokenService;
-
-class ChildAccountInfoFetcher {
- public:
- // Caller takes ownership of the fetcher and keeps it alive in order to
- // receive updates.
- static std::unique_ptr<ChildAccountInfoFetcher> CreateFrom(
- const std::string& account_id,
- AccountFetcherService* fetcher_service,
- OAuth2TokenService* token_service,
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- invalidation::InvalidationService* invalidation_service);
- virtual ~ChildAccountInfoFetcher();
-
- static void InitializeForTests();
-};
-
-#endif // COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_H_
diff --git a/chromium/components/signin/core/browser/child_account_info_fetcher_android.cc b/chromium/components/signin/core/browser/child_account_info_fetcher_android.cc
index 529906b09e8..85c6304d81b 100644
--- a/chromium/components/signin/core/browser/child_account_info_fetcher_android.cc
+++ b/chromium/components/signin/core/browser/child_account_info_fetcher_android.cc
@@ -8,6 +8,7 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
+#include "base/memory/ptr_util.h"
#include "components/signin/core/browser/account_fetcher_service.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "jni/ChildAccountInfoFetcher_jni.h"
@@ -15,9 +16,9 @@
using base::android::JavaParamRef;
// static
-std::unique_ptr<ChildAccountInfoFetcher> ChildAccountInfoFetcherAndroid::Create(
- AccountFetcherService* service,
- const std::string& account_id) {
+std::unique_ptr<ChildAccountInfoFetcherAndroid>
+ChildAccountInfoFetcherAndroid::Create(AccountFetcherService* service,
+ const std::string& account_id) {
std::string account_name =
service->account_tracker_service()->GetAccountInfo(account_id).email;
// The AccountTrackerService may not be populated correctly in tests.
@@ -25,9 +26,8 @@ std::unique_ptr<ChildAccountInfoFetcher> ChildAccountInfoFetcherAndroid::Create(
return nullptr;
// Call the constructor directly instead of using std::make_unique because the
- // constructor is private. Also, use the std::unique_ptr<> constructor instead
- // of base::WrapUnique because the _destructor_ of the subclass is private.
- return std::unique_ptr<ChildAccountInfoFetcher>(
+ // constructor is private.
+ return base::WrapUnique(
new ChildAccountInfoFetcherAndroid(service, account_id, account_name));
}
@@ -54,7 +54,6 @@ ChildAccountInfoFetcherAndroid::~ChildAccountInfoFetcherAndroid() {
void JNI_ChildAccountInfoFetcher_SetIsChildAccount(
JNIEnv* env,
- const JavaParamRef<jclass>& caller,
jlong native_service,
const JavaParamRef<jstring>& j_account_id,
jboolean is_child_account) {
diff --git a/chromium/components/signin/core/browser/child_account_info_fetcher_android.h b/chromium/components/signin/core/browser/child_account_info_fetcher_android.h
index 0b73cce4592..1007fe59fd3 100644
--- a/chromium/components/signin/core/browser/child_account_info_fetcher_android.h
+++ b/chromium/components/signin/core/browser/child_account_info_fetcher_android.h
@@ -9,15 +9,15 @@
#include <string>
#include "base/android/scoped_java_ref.h"
-#include "components/signin/core/browser/child_account_info_fetcher.h"
class AccountFetcherService;
-class ChildAccountInfoFetcherAndroid : public ChildAccountInfoFetcher {
+class ChildAccountInfoFetcherAndroid {
public:
- static std::unique_ptr<ChildAccountInfoFetcher> Create(
+ static std::unique_ptr<ChildAccountInfoFetcherAndroid> Create(
AccountFetcherService* service,
const std::string& account_id);
+ ~ChildAccountInfoFetcherAndroid();
static void InitializeForTests();
@@ -25,9 +25,7 @@ class ChildAccountInfoFetcherAndroid : public ChildAccountInfoFetcher {
ChildAccountInfoFetcherAndroid(AccountFetcherService* service,
const std::string& account_id,
const std::string& account_name);
- ~ChildAccountInfoFetcherAndroid() override;
- private:
base::android::ScopedJavaGlobalRef<jobject> j_child_account_info_fetcher_;
DISALLOW_COPY_AND_ASSIGN(ChildAccountInfoFetcherAndroid);
diff --git a/chromium/components/signin/core/browser/child_account_info_fetcher_impl.cc b/chromium/components/signin/core/browser/child_account_info_fetcher_impl.cc
deleted file mode 100644
index cc0fbf4e808..00000000000
--- a/chromium/components/signin/core/browser/child_account_info_fetcher_impl.cc
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2015 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 "components/signin/core/browser/child_account_info_fetcher_impl.h"
-
-#include "base/stl_util.h"
-#include "base/strings/string_split.h"
-#include "base/trace_event/trace_event.h"
-#include "base/values.h"
-#include "components/invalidation/public/invalidation_service.h"
-#include "components/invalidation/public/object_id_invalidation_map.h"
-#include "components/signin/core/browser/account_fetcher_service.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/signin_client.h"
-#include "google/cacheinvalidation/types.pb.h"
-#include "google_apis/gaia/gaia_auth_fetcher.h"
-#include "google_apis/gaia/gaia_constants.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-
-// TODO(maroun): Remove this file.
-
-namespace {
-
-const char kFetcherId[] = "ChildAccountInfoFetcherImpl";
-
-// Exponential backoff policy on service flag fetching failure.
-const net::BackoffEntry::Policy kBackoffPolicy = {
- 0, // Number of initial errors to ignore without backoff.
- 2000, // Initial delay for backoff in ms.
- 2, // Factor to multiply waiting time by.
- 0.2, // Fuzzing percentage. 20% will spread requests randomly between
- // 80-100% of the calculated time.
- 1000 * 60 * 60* 4, // Maximum time to delay requests by (4 hours).
- -1, // Don't discard entry even if unused.
- false, // Don't use the initial delay unless the last request was an error.
-};
-
-// The invalidation object ID used for child account graduation event.
-// The syntax is:
-// 'U' -> This is a user specific invalidation.
-// 'CA' -> Namespace used for all ChildAccount invalidations.
-// 'GRAD' -> Indicates the actual event i.e. child account graduation.
-const char kChildAccountGraduationId[] = "UCAGRAD";
-
-} // namespace
-
-ChildAccountInfoFetcherImpl::ChildAccountInfoFetcherImpl(
- const std::string& account_id,
- AccountFetcherService* fetcher_service,
- OAuth2TokenService* token_service,
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- invalidation::InvalidationService* invalidation_service)
- : OAuth2TokenService::Consumer(kFetcherId),
- token_service_(token_service),
- url_loader_factory_(url_loader_factory),
- fetcher_service_(fetcher_service),
- invalidation_service_(invalidation_service),
- account_id_(account_id),
- backoff_(&kBackoffPolicy),
- fetch_in_progress_(false) {
- TRACE_EVENT_ASYNC_BEGIN1("AccountFetcherService", kFetcherId, this,
- "account_id", account_id);
- // Invalidation service may not be available in tests.
- if (invalidation_service_) {
- invalidation_service_->RegisterInvalidationHandler(this);
- syncer::ObjectIdSet ids;
- ids.insert(invalidation::ObjectId(
- ipc::invalidation::ObjectSource::CHROME_COMPONENTS,
- kChildAccountGraduationId));
- bool insert_success =
- invalidation_service_->UpdateRegisteredInvalidationIds(this, ids);
- DCHECK(insert_success);
- }
- FetchIfNotInProgress();
-}
-
-ChildAccountInfoFetcherImpl::~ChildAccountInfoFetcherImpl() {
- TRACE_EVENT_ASYNC_END0("AccountFetcherService", kFetcherId, this);
- if (invalidation_service_)
- UnregisterInvalidationHandler();
-}
-
-void ChildAccountInfoFetcherImpl::FetchIfNotInProgress() {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (fetch_in_progress_)
- return;
- fetch_in_progress_ = true;
- OAuth2TokenService::ScopeSet scopes;
- scopes.insert(GaiaConstants::kOAuth1LoginScope);
- login_token_request_ =
- token_service_->StartRequest(account_id_, scopes, this);
-}
-
-void ChildAccountInfoFetcherImpl::OnGetTokenSuccess(
- const OAuth2TokenService::Request* request,
- const OAuth2AccessTokenConsumer::TokenResponse& token_response) {
- TRACE_EVENT_ASYNC_STEP_PAST0("AccountFetcherService", kFetcherId, this,
- "OnGetTokenSuccess");
- DCHECK_EQ(request, login_token_request_.get());
-
- gaia_auth_fetcher_ = fetcher_service_->signin_client_->CreateGaiaAuthFetcher(
- this, gaia::GaiaSource::kChrome, url_loader_factory_);
- gaia_auth_fetcher_->StartOAuthLogin(token_response.access_token,
- GaiaConstants::kGaiaService);
-}
-
-void ChildAccountInfoFetcherImpl::OnGetTokenFailure(
- const OAuth2TokenService::Request* request,
- const GoogleServiceAuthError& error) {
- HandleFailure();
-}
-
-void ChildAccountInfoFetcherImpl::OnClientLoginSuccess(
- const ClientLoginResult& result) {
- gaia_auth_fetcher_->StartGetUserInfo(result.lsid);
-}
-
-void ChildAccountInfoFetcherImpl::OnClientLoginFailure(
- const GoogleServiceAuthError& error) {
- HandleFailure();
-}
-
-void ChildAccountInfoFetcherImpl::OnGetUserInfoSuccess(
- const UserInfoMap& data) {
- auto services_iter = data.find("allServices");
- if (services_iter != data.end()) {
- std::vector<std::string> service_flags = base::SplitString(
- services_iter->second, ",", base::TRIM_WHITESPACE,
- base::SPLIT_WANT_ALL);
- bool is_child_account = base::ContainsValue(
- service_flags, AccountTrackerService::kChildAccountServiceFlag);
- if (!is_child_account && invalidation_service_) {
- // Don't bother listening for invalidations as a non-child account can't
- // become a child account.
- bool insert_success =
- invalidation_service_->UpdateRegisteredInvalidationIds(
- this, syncer::ObjectIdSet());
- DCHECK(insert_success);
- UnregisterInvalidationHandler();
- }
- fetcher_service_->SetIsChildAccount(account_id_, is_child_account);
- } else {
- DLOG(ERROR) << "ChildAccountInfoFetcherImpl::OnGetUserInfoSuccess: "
- << "GetUserInfo response didn't include allServices field.";
- }
- fetch_in_progress_ = false;
-}
-
-void ChildAccountInfoFetcherImpl::OnGetUserInfoFailure(
- const GoogleServiceAuthError& error) {
- HandleFailure();
-}
-
-void ChildAccountInfoFetcherImpl::HandleFailure() {
- fetch_in_progress_ = false;
- backoff_.InformOfRequest(false);
- timer_.Start(FROM_HERE, backoff_.GetTimeUntilRelease(), this,
- &ChildAccountInfoFetcherImpl::FetchIfNotInProgress);
-}
-
-void ChildAccountInfoFetcherImpl::UnregisterInvalidationHandler() {
- invalidation_service_->UnregisterInvalidationHandler(this);
- invalidation_service_ = nullptr;
-}
-
-void ChildAccountInfoFetcherImpl::OnInvalidatorStateChange(
- syncer::InvalidatorState state) {
- if (state == syncer::INVALIDATOR_SHUTTING_DOWN)
- UnregisterInvalidationHandler();
-}
-
-void ChildAccountInfoFetcherImpl::OnIncomingInvalidation(
- const syncer::ObjectIdInvalidationMap& invalidation_map) {
- FetchIfNotInProgress();
- invalidation_map.AcknowledgeAll();
-}
-
-std::string ChildAccountInfoFetcherImpl::GetOwnerName() const {
- return std::string(kFetcherId);
-}
diff --git a/chromium/components/signin/core/browser/child_account_info_fetcher_impl.h b/chromium/components/signin/core/browser/child_account_info_fetcher_impl.h
deleted file mode 100644
index e5383f6530d..00000000000
--- a/chromium/components/signin/core/browser/child_account_info_fetcher_impl.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2015 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 COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_IMPL_H_
-#define COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_IMPL_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/threading/thread_checker.h"
-#include "base/timer/timer.h"
-#include "components/invalidation/public/invalidation_handler.h"
-#include "components/signin/core/browser/child_account_info_fetcher.h"
-#include "google_apis/gaia/gaia_auth_consumer.h"
-#include "google_apis/gaia/oauth2_token_service.h"
-#include "net/base/backoff_entry.h"
-
-// TODO(maroun): Remove this file.
-
-namespace network {
-class SharedURLLoaderFactory;
-}
-
-class GaiaAuthFetcher;
-
-class ChildAccountInfoFetcherImpl : public ChildAccountInfoFetcher,
- public OAuth2TokenService::Consumer,
- public GaiaAuthConsumer,
- public syncer::InvalidationHandler {
- public:
- ChildAccountInfoFetcherImpl(
- const std::string& account_id,
- AccountFetcherService* fetcher_service,
- OAuth2TokenService* token_service,
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- invalidation::InvalidationService* invalidation_service);
- ~ChildAccountInfoFetcherImpl() override;
-
- private:
- void FetchIfNotInProgress();
- void HandleFailure();
- void UnregisterInvalidationHandler();
-
- // OAuth2TokenService::Consumer:
- void OnGetTokenSuccess(
- const OAuth2TokenService::Request* request,
- const OAuth2AccessTokenConsumer::TokenResponse& token_response) override;
- void OnGetTokenFailure(const OAuth2TokenService::Request* request,
- const GoogleServiceAuthError& error) override;
-
- // GaiaAuthConsumer:
- void OnClientLoginSuccess(const ClientLoginResult& result) override;
- void OnClientLoginFailure(const GoogleServiceAuthError& error) override;
- void OnGetUserInfoSuccess(const UserInfoMap& data) override;
- void OnGetUserInfoFailure(const GoogleServiceAuthError& error) override;
-
- // syncer::InvalidationHandler:
- void OnInvalidatorStateChange(syncer::InvalidatorState state) override;
- void OnIncomingInvalidation(
- const syncer::ObjectIdInvalidationMap& invalidation_map) override;
- std::string GetOwnerName() const override;
-
- OAuth2TokenService* token_service_;
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
- AccountFetcherService* fetcher_service_;
- invalidation::InvalidationService* invalidation_service_;
- const std::string account_id_;
-
- // If fetching fails, retry with exponential backoff.
- base::OneShotTimer timer_;
- net::BackoffEntry backoff_;
-
- std::unique_ptr<OAuth2TokenService::Request> login_token_request_;
- std::unique_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
-
- bool fetch_in_progress_;
- base::ThreadChecker thread_checker_;
-
- DISALLOW_COPY_AND_ASSIGN(ChildAccountInfoFetcherImpl);
-};
-
-#endif // COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_IMPL_H_
diff --git a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc
index 53aacc6b21c..5b053f49f0e 100644
--- a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc
+++ b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc
@@ -20,11 +20,12 @@ DiceAccountReconcilorDelegate::DiceAccountReconcilorDelegate(
AccountConsistencyMethod account_consistency)
: signin_client_(signin_client), account_consistency_(account_consistency) {
DCHECK(signin_client_);
+ DCHECK(DiceMethodGreaterOrEqual(account_consistency_,
+ AccountConsistencyMethod::kDiceMigration));
}
bool DiceAccountReconcilorDelegate::IsReconcileEnabled() const {
- return DiceMethodGreaterOrEqual(account_consistency_,
- AccountConsistencyMethod::kDiceMigration);
+ return true;
}
bool DiceAccountReconcilorDelegate::IsAccountConsistencyEnforced() const {
@@ -171,12 +172,9 @@ void DiceAccountReconcilorDelegate::OnReconcileFinished(
// Migration happens on startup if the last reconcile was a no-op and the
// refresh tokens are Dice-compatible.
- if (DiceMethodGreaterOrEqual(account_consistency_,
- AccountConsistencyMethod::kDiceMigration)) {
- signin_client_->SetReadyForDiceMigration(
- reconcile_is_noop && signin_client_->GetPrefs()->GetBoolean(
- prefs::kTokenServiceDiceCompatible));
- }
+ signin_client_->SetReadyForDiceMigration(
+ reconcile_is_noop && signin_client_->GetPrefs()->GetBoolean(
+ prefs::kTokenServiceDiceCompatible));
}
} // namespace signin
diff --git a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate_unittest.cc b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate_unittest.cc
index f3b36df5807..4c467559d79 100644
--- a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate_unittest.cc
+++ b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate_unittest.cc
@@ -66,15 +66,6 @@ TEST(DiceAccountReconcilorDelegateTest, OnReconcileFinished) {
DiceTestSigninClient client(&pref_service);
{
- // Dice migration not enabled.
- testing::InSequence mock_sequence;
- EXPECT_CALL(client, SetReadyForDiceMigration(testing::_)).Times(0);
- DiceAccountReconcilorDelegate delegate(
- &client, AccountConsistencyMethod::kDiceFixAuthErrors);
- delegate.OnReconcileFinished("account", true /* is_reconcile_noop */);
- }
-
- {
// Dice migration enabled, but token service is not ready.
testing::InSequence mock_sequence;
EXPECT_CALL(client, SetReadyForDiceMigration(false)).Times(1);
diff --git a/chromium/components/signin/core/browser/dice_header_helper.cc b/chromium/components/signin/core/browser/dice_header_helper.cc
index fb51916e604..4a7c91f9f36 100644
--- a/chromium/components/signin/core/browser/dice_header_helper.cc
+++ b/chromium/components/signin/core/browser/dice_header_helper.cc
@@ -20,7 +20,6 @@ namespace {
// Request parameters.
const char kRequestSigninAll[] = "all_accounts";
-const char kRequestSigninSyncAccount[] = "sync_account";
const char kRequestSignoutNoConfirmation[] = "no_confirmation";
const char kRequestSignoutShowConfirmation[] = "show_confirmation";
@@ -194,24 +193,12 @@ bool DiceHeaderHelper::IsUrlEligibleForRequestHeader(const GURL& url) {
return false;
}
- // With kDiceFixAuthError, only set the request header if the user is signed
- // in and has an authentication error.
- if (!signed_in_with_auth_error_ &&
- (account_consistency_ == AccountConsistencyMethod::kDiceFixAuthErrors)) {
- return false;
- }
-
return gaia::IsGaiaSignonRealm(url.GetOrigin());
}
std::string DiceHeaderHelper::BuildRequestHeader(
const std::string& sync_account_id,
const std::string& device_id) {
- // When fixing auth errors, only add the header when Sync is actually in error
- // state.
- DCHECK(
- signed_in_with_auth_error_ ||
- (account_consistency_ != AccountConsistencyMethod::kDiceFixAuthErrors));
DCHECK(!(sync_account_id.empty() && signed_in_with_auth_error_));
std::vector<std::string> parts;
@@ -224,10 +211,7 @@ std::string DiceHeaderHelper::BuildRequestHeader(
parts.push_back("sync_account_id=" + sync_account_id);
// Restrict Signin to Sync account only when fixing auth errors.
- std::string signin_mode =
- (account_consistency_ == AccountConsistencyMethod::kDiceFixAuthErrors)
- ? kRequestSigninSyncAccount
- : kRequestSigninAll;
+ std::string signin_mode = kRequestSigninAll;
parts.push_back("signin_mode=" + signin_mode);
// Show the signout confirmation only when Dice is fully enabled.
diff --git a/chromium/components/signin/core/browser/fake_account_fetcher_service.cc b/chromium/components/signin/core/browser/fake_account_fetcher_service.cc
index 684cb9e2e44..c855b354b10 100644
--- a/chromium/components/signin/core/browser/fake_account_fetcher_service.cc
+++ b/chromium/components/signin/core/browser/fake_account_fetcher_service.cc
@@ -28,14 +28,7 @@ void FakeAccountFetcherService::FakeUserInfoFetchSuccess(
user_info.SetString("given_name", given_name);
user_info.SetString("locale", locale);
user_info.SetString("picture", picture_url);
- account_tracker_service()->SetAccountStateFromUserInfo(account_id,
- &user_info);
-}
-
-void FakeAccountFetcherService::FakeSetIsChildAccount(
- const std::string& account_id,
- bool is_child_account) {
- SetIsChildAccount(account_id, is_child_account);
+ account_tracker_service()->SetAccountInfoFromUserInfo(account_id, &user_info);
}
void FakeAccountFetcherService::StartFetchingUserInfo(
@@ -43,11 +36,6 @@ void FakeAccountFetcherService::StartFetchingUserInfo(
// In tests, don't do actual network fetch.
}
-void FakeAccountFetcherService::StartFetchingChildInfo(
- const std::string& account_id) {
- // In tests, don't do actual network fetch.
-}
-
TestImageDecoder::TestImageDecoder() = default;
TestImageDecoder::~TestImageDecoder() = default;
diff --git a/chromium/components/signin/core/browser/fake_account_fetcher_service.h b/chromium/components/signin/core/browser/fake_account_fetcher_service.h
index 5a3cafa27c2..9e1298f2d43 100644
--- a/chromium/components/signin/core/browser/fake_account_fetcher_service.h
+++ b/chromium/components/signin/core/browser/fake_account_fetcher_service.h
@@ -33,14 +33,11 @@ class FakeAccountFetcherService : public AccountFetcherService {
const std::string& given_name,
const std::string& locale,
const std::string& picture_url);
- void FakeSetIsChildAccount(const std::string& account_id,
- bool is_child_account);
FakeAccountFetcherService();
private:
void StartFetchingUserInfo(const std::string& account_id) override;
- void StartFetchingChildInfo(const std::string& account_id) override;
DISALLOW_COPY_AND_ASSIGN(FakeAccountFetcherService);
};
diff --git a/chromium/components/signin/core/browser/fake_auth_status_provider.cc b/chromium/components/signin/core/browser/fake_auth_status_provider.cc
deleted file mode 100644
index 77e10db9d92..00000000000
--- a/chromium/components/signin/core/browser/fake_auth_status_provider.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2014 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 "components/signin/core/browser/fake_auth_status_provider.h"
-
-FakeAuthStatusProvider::FakeAuthStatusProvider(SigninErrorController* error)
- : error_provider_(error),
- auth_error_(GoogleServiceAuthError::AuthErrorNone()) {
- error_provider_->AddProvider(this);
-}
-
-FakeAuthStatusProvider::~FakeAuthStatusProvider() {
- error_provider_->RemoveProvider(this);
-}
-
-std::string FakeAuthStatusProvider::GetAccountId() const {
- return account_id_;
-}
-
-GoogleServiceAuthError FakeAuthStatusProvider::GetAuthStatus() const {
- return auth_error_;
-}
-
-void FakeAuthStatusProvider::SetAuthError(const std::string& account_id,
- const GoogleServiceAuthError& error) {
- account_id_ = account_id;
- auth_error_ = error;
- error_provider_->AuthStatusChanged();
-}
diff --git a/chromium/components/signin/core/browser/fake_auth_status_provider.h b/chromium/components/signin/core/browser/fake_auth_status_provider.h
deleted file mode 100644
index 48a03787ea1..00000000000
--- a/chromium/components/signin/core/browser/fake_auth_status_provider.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2014 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 COMPONENTS_SIGNIN_CORE_BROWSER_FAKE_AUTH_STATUS_PROVIDER_H_
-#define COMPONENTS_SIGNIN_CORE_BROWSER_FAKE_AUTH_STATUS_PROVIDER_H_
-
-#include "components/signin/core/browser/signin_error_controller.h"
-
-// Helper class that reports auth errors to SigninErrorController. Automatically
-// registers and de-registers itself as an AuthStatusProvider in the
-// constructor and destructor.
-class FakeAuthStatusProvider
- : public SigninErrorController::AuthStatusProvider {
- public:
- explicit FakeAuthStatusProvider(SigninErrorController* error);
- ~FakeAuthStatusProvider() override;
-
- // Sets the auth error that this provider reports to SigninErrorController.
- // Also notifies SigninErrorController via AuthStatusChanged().
- void SetAuthError(const std::string& account_id,
- const GoogleServiceAuthError& error);
-
- void set_error_without_status_change(const GoogleServiceAuthError& error) {
- auth_error_ = error;
- }
-
- // AuthStatusProvider implementation.
- std::string GetAccountId() const override;
- GoogleServiceAuthError GetAuthStatus() const override;
-
- private:
- SigninErrorController* error_provider_;
- std::string account_id_;
- GoogleServiceAuthError auth_error_;
-};
-
-#endif // COMPONENTS_SIGNIN_CORE_BROWSER_FAKE_AUTH_STATUS_PROVIDER_H_
diff --git a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
index 619a489a7f9..e37588f3941 100644
--- a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
+++ b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
@@ -3,9 +3,9 @@
// found in the LICENSE file.
#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
-
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "components/signin/core/browser/list_accounts_test_utils.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_urls.h"
@@ -13,79 +13,80 @@
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
+namespace {
+// Factory method to return a SharedURLLoaderFactory of our choosing.
+scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory(
+ scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory) {
+ return shared_url_loader_factory;
+}
+} // namespace
+
+FakeGaiaCookieManagerService::FakeGaiaCookieManagerService(
+ OAuth2TokenService* token_service,
+ SigninClient* client)
+ : GaiaCookieManagerService(
+ token_service,
+ client,
+ base::BindRepeating(&SigninClient::GetURLLoaderFactory,
+ base::Unretained(client))) {}
+
FakeGaiaCookieManagerService::FakeGaiaCookieManagerService(
OAuth2TokenService* token_service,
SigninClient* client,
- bool use_fake_url_loader)
- : GaiaCookieManagerService(token_service, client) {
- if (use_fake_url_loader) {
- test_url_loader_factory_ =
- std::make_unique<network::TestURLLoaderFactory>();
- shared_loader_factory_ =
- base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
- test_url_loader_factory_.get());
- }
-}
+ network::TestURLLoaderFactory* test_url_loader_factory)
+ : FakeGaiaCookieManagerService(
+ token_service,
+ client,
+ test_url_loader_factory,
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ test_url_loader_factory)) {}
+
+FakeGaiaCookieManagerService::FakeGaiaCookieManagerService(
+ OAuth2TokenService* token_service,
+ SigninClient* client,
+ network::TestURLLoaderFactory* test_url_loader_factory,
+ scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
+ shared_url_loader_factory)
+ : GaiaCookieManagerService(token_service,
+ client,
+ base::BindRepeating(&GetSharedURLLoaderFactory,
+ shared_url_loader_factory)),
+ test_url_loader_factory_(test_url_loader_factory),
+ shared_url_loader_factory_(shared_url_loader_factory) {}
FakeGaiaCookieManagerService::~FakeGaiaCookieManagerService() {
- if (shared_loader_factory_)
- shared_loader_factory_->Detach();
+ if (shared_url_loader_factory_)
+ shared_url_loader_factory_->Detach();
}
void FakeGaiaCookieManagerService::SetListAccountsResponseHttpNotFound() {
- test_url_loader_factory_->AddResponse(
- GaiaUrls::GetInstance()
- ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
- .spec(),
- /*content=*/"", net::HTTP_NOT_FOUND);
+ signin::SetListAccountsResponseHttpNotFound(test_url_loader_factory_);
}
void FakeGaiaCookieManagerService::SetListAccountsResponseWebLoginRequired() {
- test_url_loader_factory_->AddResponse(
- GaiaUrls::GetInstance()
- ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
- .spec(),
- "Info=WebLoginRequired");
+ signin::SetListAccountsResponseWebLoginRequired(test_url_loader_factory_);
}
void FakeGaiaCookieManagerService::SetListAccountsResponseWithParams(
- const std::vector<CookieParams>& params) {
- std::vector<std::string> response_body;
- for (const auto& param : params) {
- std::string response_part = base::StringPrintf(
- "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"%s\"",
- param.email.c_str(), param.valid ? 1 : 0, param.gaia_id.c_str());
- if (param.signed_out || !param.verified) {
- response_part +=
- base::StringPrintf(", null, null, null, %d, %d",
- param.signed_out ? 1 : 0, param.verified ? 1 : 0);
- }
- response_part += "]";
- response_body.push_back(response_part);
- }
-
- test_url_loader_factory_->AddResponse(
- GaiaUrls::GetInstance()
- ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
- .spec(),
- std::string("[\"f\", [") + base::JoinString(response_body, ", ") + "]]");
+ const std::vector<signin::CookieParams>& params) {
+ signin::SetListAccountsResponseWithParams(params, test_url_loader_factory_);
}
void FakeGaiaCookieManagerService::SetListAccountsResponseNoAccounts() {
- SetListAccountsResponseWithParams({});
+ signin::SetListAccountsResponseNoAccounts(test_url_loader_factory_);
}
void FakeGaiaCookieManagerService::SetListAccountsResponseOneAccount(
const std::string& email,
const std::string& gaia_id) {
- CookieParams params = {email, gaia_id, true /* valid */,
- false /* signed_out */, true /* verified */};
- SetListAccountsResponseWithParams({params});
+ signin::SetListAccountsResponseOneAccount(email, gaia_id,
+ test_url_loader_factory_);
}
void FakeGaiaCookieManagerService::SetListAccountsResponseOneAccountWithParams(
- const CookieParams& params) {
- SetListAccountsResponseWithParams({params});
+ const signin::CookieParams& params) {
+ signin::SetListAccountsResponseOneAccountWithParams(params,
+ test_url_loader_factory_);
}
void FakeGaiaCookieManagerService::SetListAccountsResponseTwoAccounts(
@@ -93,16 +94,6 @@ void FakeGaiaCookieManagerService::SetListAccountsResponseTwoAccounts(
const std::string& gaia_id1,
const std::string& email2,
const std::string& gaia_id2) {
- SetListAccountsResponseWithParams(
- {{email1, gaia_id1, true /* valid */, false /* signed_out */,
- true /* verified */},
- {email2, gaia_id2, true /* valid */, false /* signed_out */,
- true /* verified */}});
-}
-
-scoped_refptr<network::SharedURLLoaderFactory>
-FakeGaiaCookieManagerService::GetURLLoaderFactory() {
- return shared_loader_factory_
- ? shared_loader_factory_
- : GaiaCookieManagerService::GetURLLoaderFactory();
+ signin::SetListAccountsResponseTwoAccounts(email1, gaia_id1, email2, gaia_id2,
+ test_url_loader_factory_);
}
diff --git a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h
index 66a67cdb0b8..9da87b92636 100644
--- a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h
+++ b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h
@@ -10,50 +10,61 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "components/signin/core/browser/gaia_cookie_manager_service.h"
+#include "components/signin/core/browser/list_accounts_test_utils.h"
+#include "services/network/test/test_url_loader_factory.h"
namespace network {
-class TestURLLoaderFactory;
class WeakWrapperSharedURLLoaderFactory;
}
class FakeGaiaCookieManagerService : public GaiaCookieManagerService {
public:
- // Parameters for the fake ListAccounts response.
- struct CookieParams {
- std::string email;
- std::string gaia_id;
- bool valid;
- bool signed_out;
- bool verified;
- };
-
+ // Convenience constructor overload which uses the SharedURLLoaderFactory from
+ // SigninClient.
FakeGaiaCookieManagerService(OAuth2TokenService* token_service,
- SigninClient* client,
- bool use_fake_url_fetcher = true);
+ SigninClient* client);
+
+ // Constructor overload for tests that want to use a TestURLLoaderFactory for
+ // cookie related requests.
+ FakeGaiaCookieManagerService(
+ OAuth2TokenService* token_service,
+ SigninClient* client,
+ network::TestURLLoaderFactory* test_url_loader_factory);
+
~FakeGaiaCookieManagerService() override;
void SetListAccountsResponseHttpNotFound();
void SetListAccountsResponseWebLoginRequired();
void SetListAccountsResponseWithParams(
- const std::vector<CookieParams>& params);
+ const std::vector<signin::CookieParams>& params);
// Helper methods, equivalent to calling SetListAccountsResponseWithParams().
void SetListAccountsResponseNoAccounts();
void SetListAccountsResponseOneAccount(const std::string& email,
const std::string& gaia_id);
- void SetListAccountsResponseOneAccountWithParams(const CookieParams& params);
+ void SetListAccountsResponseOneAccountWithParams(
+ const signin::CookieParams& params);
void SetListAccountsResponseTwoAccounts(const std::string& email1,
const std::string& gaia_id1,
const std::string& email2,
const std::string& gaia_id2);
private:
- scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
+ // Internal constructor which does the actual construction.
+ FakeGaiaCookieManagerService(
+ OAuth2TokenService* token_service,
+ SigninClient* client,
+ network::TestURLLoaderFactory* test_url_loader_factory,
+ scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
+ shared_url_loader_factory);
+
+ // Provides a fake response for calls to /ListAccounts.
+ // Owned by the client if passed in via the constructor that takes in this
+ // pointer; null otherwise.
+ network::TestURLLoaderFactory* test_url_loader_factory_ = nullptr;
- // Provide a fake response for calls to /ListAccounts.
- std::unique_ptr<network::TestURLLoaderFactory> test_url_loader_factory_;
scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
- shared_loader_factory_;
+ shared_url_loader_factory_;
DISALLOW_COPY_AND_ASSIGN(FakeGaiaCookieManagerService);
};
diff --git a/chromium/components/signin/core/browser/fake_signin_manager.cc b/chromium/components/signin/core/browser/fake_signin_manager.cc
index 8013a5ec1b4..8fe75e3c647 100644
--- a/chromium/components/signin/core/browser/fake_signin_manager.cc
+++ b/chromium/components/signin/core/browser/fake_signin_manager.cc
@@ -14,11 +14,9 @@
FakeSigninManagerBase::FakeSigninManagerBase(
SigninClient* client,
- AccountTrackerService* account_tracker_service,
- SigninErrorController* signin_error_controller)
- : SigninManagerBase(client,
- account_tracker_service,
- signin_error_controller) {}
+ ProfileOAuth2TokenService* token_service,
+ AccountTrackerService* account_tracker_service)
+ : SigninManagerBase(client, token_service, account_tracker_service) {}
FakeSigninManagerBase::~FakeSigninManagerBase() {}
@@ -37,20 +35,6 @@ FakeSigninManager::FakeSigninManager(
token_service,
account_tracker_service,
cookie_manager_service,
- nullptr,
- signin::AccountConsistencyMethod::kDisabled) {}
-
-FakeSigninManager::FakeSigninManager(
- SigninClient* client,
- ProfileOAuth2TokenService* token_service,
- AccountTrackerService* account_tracker_service,
- GaiaCookieManagerService* cookie_manager_service,
- SigninErrorController* signin_error_controller)
- : FakeSigninManager(client,
- token_service,
- account_tracker_service,
- cookie_manager_service,
- signin_error_controller,
signin::AccountConsistencyMethod::kDisabled) {}
FakeSigninManager::FakeSigninManager(
@@ -58,13 +42,11 @@ FakeSigninManager::FakeSigninManager(
ProfileOAuth2TokenService* token_service,
AccountTrackerService* account_tracker_service,
GaiaCookieManagerService* cookie_manager_service,
- SigninErrorController* signin_error_controller,
signin::AccountConsistencyMethod account_consistency)
: SigninManager(client,
token_service,
account_tracker_service,
cookie_manager_service,
- signin_error_controller,
account_consistency),
token_service_(token_service) {}
diff --git a/chromium/components/signin/core/browser/fake_signin_manager.h b/chromium/components/signin/core/browser/fake_signin_manager.h
index 33a2af3bc5a..5c7de4a6737 100644
--- a/chromium/components/signin/core/browser/fake_signin_manager.h
+++ b/chromium/components/signin/core/browser/fake_signin_manager.h
@@ -17,10 +17,9 @@
class FakeSigninManagerBase : public SigninManagerBase {
public:
- FakeSigninManagerBase(
- SigninClient* client,
- AccountTrackerService* account_tracker_service,
- SigninErrorController* signin_error_controller = nullptr);
+ FakeSigninManagerBase(SigninClient* client,
+ ProfileOAuth2TokenService* token_service,
+ AccountTrackerService* account_tracker_service);
~FakeSigninManagerBase() override;
void SignIn(const std::string& account_id);
@@ -41,13 +40,6 @@ class FakeSigninManager : public SigninManager {
ProfileOAuth2TokenService* token_service,
AccountTrackerService* account_tracker_service,
GaiaCookieManagerService* cookie_manager_service,
- SigninErrorController* signin_error_controller);
-
- FakeSigninManager(SigninClient* client,
- ProfileOAuth2TokenService* token_service,
- AccountTrackerService* account_tracker_service,
- GaiaCookieManagerService* cookie_manager_service,
- SigninErrorController* signin_error_controller,
signin::AccountConsistencyMethod account_consistency);
~FakeSigninManager() override;
diff --git a/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc b/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
index b9020bde77a..b9aa8215508 100644
--- a/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -20,6 +20,7 @@
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/signin_metrics.h"
+#include "components/signin/core/browser/ubertoken_fetcher_impl.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/oauth2_token_service.h"
@@ -156,8 +157,7 @@ GaiaCookieManagerService::GaiaCookieRequest::GaiaCookieRequest(
account_ids_(other.account_ids()),
source_(other.source()) {}
-GaiaCookieManagerService::GaiaCookieRequest::~GaiaCookieRequest() {
-}
+GaiaCookieManagerService::GaiaCookieRequest::~GaiaCookieRequest() {}
const std::string GaiaCookieManagerService::GaiaCookieRequest::GetAccountID() {
DCHECK_EQ(request_type_, GaiaCookieRequestType::ADD_ACCOUNT);
@@ -420,17 +420,28 @@ void GaiaCookieManagerService::ExternalCcResultFetcher::
GaiaCookieManagerService::GaiaCookieManagerService(
OAuth2TokenService* token_service,
SigninClient* signin_client)
+ : GaiaCookieManagerService(
+ token_service,
+ signin_client,
+ base::BindRepeating(&SigninClient::GetURLLoaderFactory,
+ base::Unretained(signin_client))) {}
+
+GaiaCookieManagerService::GaiaCookieManagerService(
+ OAuth2TokenService* token_service,
+ SigninClient* signin_client,
+ base::RepeatingCallback<scoped_refptr<network::SharedURLLoaderFactory>()>
+ shared_url_loader_factory_getter)
: OAuth2TokenService::Consumer("gaia_cookie_manager"),
token_service_(token_service),
signin_client_(signin_client),
+ shared_url_loader_factory_getter_(shared_url_loader_factory_getter),
external_cc_result_fetcher_(this),
fetcher_backoff_(&kBackoffPolicy),
fetcher_retries_(0),
cookie_listener_binding_(this),
external_cc_result_fetched_(false),
list_accounts_stale_(true),
- weak_ptr_factory_(this) {
-}
+ weak_ptr_factory_(this) {}
GaiaCookieManagerService::~GaiaCookieManagerService() {
CancelAll();
@@ -507,8 +518,8 @@ void GaiaCookieManagerService::AddAccountToCookieInternal(
gaia::GaiaSource source) {
DCHECK(!account_id.empty());
if (!signin_client_->AreSigninCookiesAllowed()) {
- SignalComplete(account_id,
- GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
+ SignalComplete(account_id, GoogleServiceAuthError(
+ GoogleServiceAuthError::REQUEST_CANCELED));
return;
}
@@ -616,8 +627,8 @@ void GaiaCookieManagerService::LogOutAllAccounts(gaia::GaiaSource source) {
// Remove all but the executing request. Re-add all requests being kept.
if (requests_.size() > 1) {
requests_.erase(requests_.begin() + 1, requests_.end());
- requests_.insert(
- requests_.end(), requests_to_keep.begin(), requests_to_keep.end());
+ requests_.insert(requests_.end(), requests_to_keep.begin(),
+ requests_to_keep.end());
}
}
@@ -649,7 +660,7 @@ void GaiaCookieManagerService::CancelAll() {
scoped_refptr<network::SharedURLLoaderFactory>
GaiaCookieManagerService::GetURLLoaderFactory() {
- return signin_client_->GetURLLoaderFactory();
+ return shared_url_loader_factory_getter_.Run();
}
void GaiaCookieManagerService::OnCookieChange(
@@ -703,10 +714,21 @@ void GaiaCookieManagerService::SignalSetAccountsComplete(
observer.OnSetAccountsInCookieCompleted(error);
}
-void GaiaCookieManagerService::OnUbertokenSuccess(
+void GaiaCookieManagerService::OnUbertokenFetchComplete(
+ GoogleServiceAuthError error,
const std::string& uber_token) {
+ if (error != GoogleServiceAuthError::AuthErrorNone()) {
+ // Note that the UberToken fetcher already retries transient errors.
+ const std::string account_id = requests_.front().GetAccountID();
+ VLOG(1) << "Failed to retrieve ubertoken"
+ << " account=" << account_id << " error=" << error.ToString();
+ HandleNextRequest();
+ SignalComplete(account_id, error);
+ return;
+ }
+
DCHECK(requests_.front().request_type() ==
- GaiaCookieRequestType::ADD_ACCOUNT);
+ GaiaCookieRequestType::ADD_ACCOUNT);
VLOG(1) << "GaiaCookieManagerService::OnUbertokenSuccess"
<< " account=" << requests_.front().GetAccountID();
fetcher_retries_ = 0;
@@ -723,16 +745,6 @@ void GaiaCookieManagerService::OnUbertokenSuccess(
base::Unretained(this)));
}
-void GaiaCookieManagerService::OnUbertokenFailure(
- const GoogleServiceAuthError& error) {
- // Note that the UberToken fetcher already retries transient errors.
- const std::string account_id = requests_.front().GetAccountID();
- VLOG(1) << "Failed to retrieve ubertoken"
- << " account=" << account_id << " error=" << error.ToString();
- HandleNextRequest();
- SignalComplete(account_id, error);
-}
-
void GaiaCookieManagerService::OnTokenFetched(const std::string& account_id,
const std::string& token) {
access_tokens_.insert(std::make_pair(account_id, token));
@@ -805,8 +817,8 @@ void GaiaCookieManagerService::OnMergeSessionFailure(
if (++fetcher_retries_ < signin::kMaxFetcherRetries &&
error.IsTransientError()) {
fetcher_backoff_.InformOfRequest(false);
- UMA_HISTOGRAM_ENUMERATION("OAuth2Login.MergeSessionRetry",
- error.state(), GoogleServiceAuthError::NUM_STATES);
+ UMA_HISTOGRAM_ENUMERATION("OAuth2Login.MergeSessionRetry", error.state(),
+ GoogleServiceAuthError::NUM_STATES);
fetcher_timer_.Start(
FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(),
base::BindOnce(
@@ -818,8 +830,8 @@ void GaiaCookieManagerService::OnMergeSessionFailure(
uber_token_ = std::string();
- UMA_HISTOGRAM_ENUMERATION("OAuth2Login.MergeSessionFailure",
- error.state(), GoogleServiceAuthError::NUM_STATES);
+ UMA_HISTOGRAM_ENUMERATION("OAuth2Login.MergeSessionFailure", error.state(),
+ GoogleServiceAuthError::NUM_STATES);
HandleNextRequest();
SignalComplete(account_id, error);
}
@@ -876,8 +888,8 @@ void GaiaCookieManagerService::OnListAccountsSuccess(const std::string& data) {
GaiaCookieRequestType::LIST_ACCOUNTS);
fetcher_backoff_.InformOfRequest(true);
- if (!gaia::ParseListAccountsData(
- data, &listed_accounts_, &signed_out_accounts_)) {
+ if (!gaia::ParseListAccountsData(data, &listed_accounts_,
+ &signed_out_accounts_)) {
listed_accounts_.clear();
signed_out_accounts_.clear();
GoogleServiceAuthError error(
@@ -920,8 +932,8 @@ void GaiaCookieManagerService::OnListAccountsFailure(
if (++fetcher_retries_ < signin::kMaxFetcherRetries &&
error.IsTransientError()) {
fetcher_backoff_.InformOfRequest(false);
- UMA_HISTOGRAM_ENUMERATION("Signin.ListAccountsRetry",
- error.state(), GoogleServiceAuthError::NUM_STATES);
+ UMA_HISTOGRAM_ENUMERATION("Signin.ListAccountsRetry", error.state(),
+ GoogleServiceAuthError::NUM_STATES);
fetcher_timer_.Start(
FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(),
base::BindOnce(
@@ -996,8 +1008,11 @@ void GaiaCookieManagerService::StartFetchingUbertoken() {
const std::string account_id = requests_.front().GetAccountID();
VLOG(1) << "GaiaCookieManagerService::StartFetchingUbertoken account_id="
<< requests_.front().GetAccountID();
- uber_token_fetcher_ = std::make_unique<UbertokenFetcher>(
- token_service_, this, GetURLLoaderFactory(),
+ uber_token_fetcher_ = std::make_unique<signin::UbertokenFetcherImpl>(
+ account_id, access_token_, token_service_,
+ base::BindOnce(&GaiaCookieManagerService::OnUbertokenFetchComplete,
+ base::Unretained(this)),
+ GetURLLoaderFactory(),
base::BindRepeating(
[](SigninClient* client, GaiaAuthConsumer* consumer,
scoped_refptr<network::SharedURLLoaderFactory> url_loader)
@@ -1006,12 +1021,6 @@ void GaiaCookieManagerService::StartFetchingUbertoken() {
consumer, gaia::GaiaSource::kChrome, url_loader);
},
base::Unretained(signin_client_)));
- if (access_token_.empty()) {
- uber_token_fetcher_->StartFetchingToken(account_id);
- } else {
- uber_token_fetcher_->StartFetchingTokenWithAccessToken(account_id,
- access_token_);
- }
}
void GaiaCookieManagerService::StartFetchingMultiLogin(
@@ -1027,8 +1036,8 @@ void GaiaCookieManagerService::StartFetchingMergeSession() {
gaia_auth_fetcher_ = signin_client_->CreateGaiaAuthFetcher(
this, requests_.front().source(), GetURLLoaderFactory());
- gaia_auth_fetcher_->StartMergeSession(uber_token_,
- external_cc_result_fetcher_.GetExternalCcResult());
+ gaia_auth_fetcher_->StartMergeSession(
+ uber_token_, external_cc_result_fetcher_.GetExternalCcResult());
}
void GaiaCookieManagerService::StartGaiaLogOut() {
@@ -1113,7 +1122,7 @@ void GaiaCookieManagerService::HandleNextRequest() {
GaiaCookieRequestType::LIST_ACCOUNTS) {
// This and any directly subsequent list accounts would return the same.
while (!requests_.empty() && requests_.front().request_type() ==
- GaiaCookieRequestType::LIST_ACCOUNTS) {
+ GaiaCookieRequestType::LIST_ACCOUNTS) {
requests_.pop_front();
}
} else {
diff --git a/chromium/components/signin/core/browser/gaia_cookie_manager_service.h b/chromium/components/signin/core/browser/gaia_cookie_manager_service.h
index c9305f706dc..0e62a0bdbb0 100644
--- a/chromium/components/signin/core/browser/gaia_cookie_manager_service.h
+++ b/chromium/components/signin/core/browser/gaia_cookie_manager_service.h
@@ -12,6 +12,7 @@
#include <utility>
#include <vector>
+#include "base/callback.h"
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
@@ -21,8 +22,8 @@
#include "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/gaia_auth_fetcher.h"
#include "google_apis/gaia/gaia_auth_util.h"
+#include "google_apis/gaia/oauth2_token_service.h"
#include "google_apis/gaia/oauth_multilogin_result.h"
-#include "google_apis/gaia/ubertoken_fetcher.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "net/base/backoff_entry.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
@@ -30,14 +31,16 @@
class GaiaAuthFetcher;
class GaiaCookieRequest;
class GoogleServiceAuthError;
-class OAuth2TokenService;
namespace network {
class SharedURLLoaderFactory;
class SimpleURLLoader;
-}
+} // namespace network
namespace signin {
+
+class UbertokenFetcherImpl;
+
// The maximum number of retries for a fetcher used in this class.
constexpr int kMaxFetcherRetries = 8;
@@ -68,7 +71,6 @@ struct MultiloginParameters {
// lifetime of this object, when the first call is made to AddAccountToCookie.
class GaiaCookieManagerService : public KeyedService,
public GaiaAuthConsumer,
- public UbertokenConsumer,
public network::mojom::CookieChangeListener,
public OAuth2TokenService::Consumer {
public:
@@ -214,6 +216,20 @@ class GaiaCookieManagerService : public KeyedService,
GaiaCookieManagerService(OAuth2TokenService* token_service,
SigninClient* signin_client);
+
+ // Creates a GaiaCookieManagerService that uses the provided
+ // |shared_url_loader_factory_getter| to determine the SharedUrlLoaderFactory
+ // used for cookie-related requests.
+ // Note: SharedUrlLoaderFactory is passed via callback, so that if the
+ // callback has side-effects (e.g. network initialization), they do not occur
+ // until the first time GaiaCookieManagerService::GetSharedUrlLoaderFactory is
+ // called.
+ GaiaCookieManagerService(
+ OAuth2TokenService* token_service,
+ SigninClient* signin_client,
+ base::RepeatingCallback<scoped_refptr<network::SharedURLLoaderFactory>()>
+ shared_url_loader_factory_getter);
+
~GaiaCookieManagerService() override;
void InitCookieListener();
@@ -286,12 +302,13 @@ class GaiaCookieManagerService : public KeyedService,
}
// Returns a non-NULL pointer to its instance of net::BackoffEntry
- const net::BackoffEntry* GetBackoffEntry() {
- return &fetcher_backoff_;
- }
+ const net::BackoffEntry* GetBackoffEntry() { return &fetcher_backoff_; }
+
+ scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory();
- // Can be overridden by tests.
- virtual scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory();
+ // Ubertoken fetch completion callback. Called by unittests directly.
+ void OnUbertokenFetchComplete(GoogleServiceAuthError error,
+ const std::string& uber_token);
private:
FRIEND_TEST_ALL_PREFIXES(GaiaCookieManagerServiceTest,
@@ -314,10 +331,6 @@ class GaiaCookieManagerService : public KeyedService,
network::mojom::CookieChangeCause cause) override;
void OnCookieListenerConnectionError();
- // Overridden from UbertokenConsumer.
- void OnUbertokenSuccess(const std::string& token) override;
- void OnUbertokenFailure(const GoogleServiceAuthError& error) override;
-
// Overridden from OAuth2TokenService::Consumer.
void OnGetTokenSuccess(
const OAuth2TokenService::Request* request,
@@ -388,8 +401,11 @@ class GaiaCookieManagerService : public KeyedService,
OAuth2TokenService* token_service_;
SigninClient* signin_client_;
+
+ base::RepeatingCallback<scoped_refptr<network::SharedURLLoaderFactory>()>
+ shared_url_loader_factory_getter_;
std::unique_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
- std::unique_ptr<UbertokenFetcher> uber_token_fetcher_;
+ std::unique_ptr<signin::UbertokenFetcherImpl> uber_token_fetcher_;
ExternalCcResultFetcher external_cc_result_fetcher_;
// If the GaiaAuthFetcher or SimpleURLLoader fails, retry with exponential
diff --git a/chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc b/chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
index 170eb8d26e4..2cbf0fc474f 100644
--- a/chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
+++ b/chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
@@ -12,11 +12,11 @@
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_task_environment.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/prefs/pref_registry_simple.h"
@@ -47,6 +47,7 @@ class MockObserver : public GaiaCookieManagerService::Observer {
void(const std::vector<gaia::ListedAccount>&,
const std::vector<gaia::ListedAccount>&,
const GoogleServiceAuthError&));
+
private:
GaiaCookieManagerService* helper_;
@@ -90,11 +91,13 @@ MATCHER_P(ListedAccountEquals, expected, "") {
class InstrumentedGaiaCookieManagerService : public GaiaCookieManagerService {
public:
- InstrumentedGaiaCookieManagerService(
- OAuth2TokenService* token_service,
- SigninClient* signin_client)
- : GaiaCookieManagerService(token_service,
- signin_client) {
+ InstrumentedGaiaCookieManagerService(OAuth2TokenService* token_service,
+ SigninClient* signin_client)
+ : GaiaCookieManagerService(
+ token_service,
+ signin_client,
+ base::BindRepeating(&SigninClient::GetURLLoaderFactory,
+ base::Unretained(signin_client))) {
total++;
}
@@ -138,14 +141,15 @@ class GaiaCookieManagerServiceTest : public testing::Test {
OAuth2TokenService* token_service() { return &token_service_; }
TestSigninClient* signin_client() { return signin_client_.get(); }
- void SimulateUbertokenSuccess(UbertokenConsumer* consumer,
+ void SimulateUbertokenSuccess(GaiaCookieManagerService* gcms,
const std::string& uber_token) {
- consumer->OnUbertokenSuccess(uber_token);
+ gcms->OnUbertokenFetchComplete(
+ GoogleServiceAuthError(GoogleServiceAuthError::NONE), uber_token);
}
- void SimulateUbertokenFailure(UbertokenConsumer* consumer,
+ void SimulateUbertokenFailure(GaiaCookieManagerService* gcms,
const GoogleServiceAuthError& error) {
- consumer->OnUbertokenFailure(error);
+ gcms->OnUbertokenFetchComplete(error, /*uber_token=*/std::string());
}
void SimulateAccessTokenFailure(OAuth2TokenService::Consumer* consumer,
@@ -231,7 +235,7 @@ class GaiaCookieManagerServiceTest : public testing::Test {
}
private:
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment task_environment_;
FakeOAuth2TokenService token_service_;
GoogleServiceAuthError no_error_;
GoogleServiceAuthError error_;
@@ -249,8 +253,8 @@ TEST_F(GaiaCookieManagerServiceTest, Success) {
MockObserver observer(&helper);
EXPECT_CALL(helper, StartFetchingUbertoken());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc1@gmail.com", no_error()));
helper.AddAccountToCookie("acc1@gmail.com", gaia::GaiaSource::kChrome);
SimulateMergeSessionSuccess(&helper, "token");
@@ -262,15 +266,15 @@ TEST_F(GaiaCookieManagerServiceTest, FailedMergeSession) {
base::HistogramTester histograms;
EXPECT_CALL(helper, StartFetchingUbertoken());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
- error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc1@gmail.com", error()));
helper.AddAccountToCookie("acc1@gmail.com", gaia::GaiaSource::kChrome);
SimulateMergeSessionFailure(&helper, error());
// Persistent error incurs no further retries.
DCHECK(!helper.is_running());
histograms.ExpectUniqueSample("OAuth2Login.MergeSessionFailure",
- GoogleServiceAuthError::SERVICE_ERROR, 1);
+ GoogleServiceAuthError::SERVICE_ERROR, 1);
}
TEST_F(GaiaCookieManagerServiceTest, AddAccountCookiesDisabled) {
@@ -278,8 +282,8 @@ TEST_F(GaiaCookieManagerServiceTest, AddAccountCookiesDisabled) {
MockObserver observer(&helper);
signin_client()->set_are_signin_cookies_allowed(false);
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
- canceled()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc1@gmail.com", canceled()));
helper.AddAccountToCookie("acc1@gmail.com", gaia::GaiaSource::kChrome);
}
@@ -294,8 +298,8 @@ TEST_F(GaiaCookieManagerServiceTest, MergeSessionRetried) {
EXPECT_CALL(helper, StartFetchingUbertoken());
EXPECT_CALL(helper, StartFetchingMergeSession());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc1@gmail.com", no_error()));
helper.AddAccountToCookie("acc1@gmail.com", gaia::GaiaSource::kChrome);
SimulateMergeSessionFailure(&helper, canceled());
@@ -316,8 +320,8 @@ TEST_F(GaiaCookieManagerServiceTest, MergeSessionRetriedTwice) {
EXPECT_CALL(helper, StartFetchingUbertoken());
EXPECT_CALL(helper, StartFetchingMergeSession()).Times(2);
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc1@gmail.com", no_error()));
helper.AddAccountToCookie("acc1@gmail.com", gaia::GaiaSource::kChrome);
SimulateMergeSessionFailure(&helper, canceled());
@@ -329,7 +333,7 @@ TEST_F(GaiaCookieManagerServiceTest, MergeSessionRetriedTwice) {
SimulateMergeSessionSuccess(&helper, "token");
DCHECK(!helper.is_running());
histograms.ExpectUniqueSample("OAuth2Login.MergeSessionRetry",
- GoogleServiceAuthError::REQUEST_CANCELED, 2);
+ GoogleServiceAuthError::REQUEST_CANCELED, 2);
}
TEST_F(GaiaCookieManagerServiceTest, FailedUbertoken) {
@@ -337,8 +341,8 @@ TEST_F(GaiaCookieManagerServiceTest, FailedUbertoken) {
MockObserver observer(&helper);
EXPECT_CALL(helper, StartFetchingUbertoken());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
- error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc1@gmail.com", error()));
helper.AddAccountToCookie("acc1@gmail.com", gaia::GaiaSource::kChrome);
SimulateUbertokenFailure(&helper, error());
@@ -874,10 +878,10 @@ TEST_F(GaiaCookieManagerServiceTest, ContinueAfterSuccess) {
MockObserver observer(&helper);
EXPECT_CALL(helper, StartFetchingUbertoken()).Times(2);
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
- no_error()));
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc1@gmail.com", no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc2@gmail.com", no_error()));
helper.AddAccountToCookie("acc1@gmail.com", gaia::GaiaSource::kChrome);
helper.AddAccountToCookie("acc2@gmail.com", gaia::GaiaSource::kChrome);
@@ -890,10 +894,10 @@ TEST_F(GaiaCookieManagerServiceTest, ContinueAfterFailure1) {
MockObserver observer(&helper);
EXPECT_CALL(helper, StartFetchingUbertoken()).Times(2);
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
- error()));
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc1@gmail.com", error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc2@gmail.com", no_error()));
helper.AddAccountToCookie("acc1@gmail.com", gaia::GaiaSource::kChrome);
helper.AddAccountToCookie("acc2@gmail.com", gaia::GaiaSource::kChrome);
@@ -906,10 +910,10 @@ TEST_F(GaiaCookieManagerServiceTest, ContinueAfterFailure2) {
MockObserver observer(&helper);
EXPECT_CALL(helper, StartFetchingUbertoken()).Times(2);
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
- error()));
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc1@gmail.com", error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc2@gmail.com", no_error()));
helper.AddAccountToCookie("acc1@gmail.com", gaia::GaiaSource::kChrome);
helper.AddAccountToCookie("acc2@gmail.com", gaia::GaiaSource::kChrome);
@@ -944,8 +948,8 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsNoQueue) {
MockObserver observer(&helper);
EXPECT_CALL(helper, StartFetchingUbertoken());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc2@gmail.com", no_error()));
EXPECT_CALL(helper, StartFetchingLogOut());
helper.AddAccountToCookie("acc2@gmail.com", gaia::GaiaSource::kChrome);
@@ -961,8 +965,8 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsFails) {
MockObserver observer(&helper);
EXPECT_CALL(helper, StartFetchingUbertoken());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc2@gmail.com", no_error()));
EXPECT_CALL(helper, StartFetchingLogOut());
helper.AddAccountToCookie("acc2@gmail.com", gaia::GaiaSource::kChrome);
@@ -979,8 +983,8 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsAfterOneAddInQueue) {
MockObserver observer(&helper);
EXPECT_CALL(helper, StartFetchingUbertoken());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc2@gmail.com", no_error()));
EXPECT_CALL(helper, StartFetchingLogOut());
helper.AddAccountToCookie("acc2@gmail.com", gaia::GaiaSource::kChrome);
@@ -995,10 +999,10 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsAfterTwoAddsInQueue) {
MockObserver observer(&helper);
EXPECT_CALL(helper, StartFetchingUbertoken());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
- no_error()));
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
- canceled()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc1@gmail.com", no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc2@gmail.com", canceled()));
EXPECT_CALL(helper, StartFetchingLogOut());
helper.AddAccountToCookie("acc1@gmail.com", gaia::GaiaSource::kChrome);
@@ -1015,8 +1019,8 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsTwice) {
MockObserver observer(&helper);
EXPECT_CALL(helper, StartFetchingUbertoken());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc2@gmail.com", no_error()));
EXPECT_CALL(helper, StartFetchingLogOut());
helper.AddAccountToCookie("acc2@gmail.com", gaia::GaiaSource::kChrome);
@@ -1033,11 +1037,11 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsBeforeAdd) {
MockObserver observer(&helper);
EXPECT_CALL(helper, StartFetchingUbertoken()).Times(2);
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc2@gmail.com", no_error()));
EXPECT_CALL(helper, StartFetchingLogOut());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc3@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc3@gmail.com", no_error()));
helper.AddAccountToCookie("acc2@gmail.com", gaia::GaiaSource::kChrome);
SimulateMergeSessionSuccess(&helper, "token1");
@@ -1053,13 +1057,12 @@ TEST_F(GaiaCookieManagerServiceTest, LogOutAllAccountsBeforeLogoutAndAdd) {
InstrumentedGaiaCookieManagerService helper(token_service(), signin_client());
MockObserver observer(&helper);
-
EXPECT_CALL(helper, StartFetchingUbertoken()).Times(2);
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc2@gmail.com", no_error()));
EXPECT_CALL(helper, StartFetchingLogOut());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc3@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc3@gmail.com", no_error()));
helper.AddAccountToCookie("acc2@gmail.com", gaia::GaiaSource::kChrome);
SimulateMergeSessionSuccess(&helper, "token1");
@@ -1079,13 +1082,13 @@ TEST_F(GaiaCookieManagerServiceTest, PendingSigninThenSignout) {
MockObserver observer(&helper);
// From the first Signin.
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc1@gmail.com", no_error()));
// From the sign out and then re-sign in.
EXPECT_CALL(helper, StartFetchingLogOut());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc3@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc3@gmail.com", no_error()));
// Total sign in 2 times, not enforcing ordered sequences.
EXPECT_CALL(helper, StartFetchingUbertoken()).Times(2);
@@ -1105,10 +1108,10 @@ TEST_F(GaiaCookieManagerServiceTest, CancelSignIn) {
MockObserver observer(&helper);
EXPECT_CALL(helper, StartFetchingUbertoken());
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc2@gmail.com",
- canceled()));
- EXPECT_CALL(observer, OnAddAccountToCookieCompleted("acc1@gmail.com",
- no_error()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc2@gmail.com", canceled()));
+ EXPECT_CALL(observer,
+ OnAddAccountToCookieCompleted("acc1@gmail.com", no_error()));
EXPECT_CALL(helper, StartFetchingLogOut());
helper.AddAccountToCookie("acc1@gmail.com", gaia::GaiaSource::kChrome);
@@ -1156,7 +1159,8 @@ TEST_F(GaiaCookieManagerServiceTest, ListAccountsFindsOneAccount) {
ASSERT_FALSE(helper.ListAccounts(&list_accounts, &signed_out_accounts));
- SimulateListAccountsSuccess(&helper,
+ SimulateListAccountsSuccess(
+ &helper,
"[\"f\", [[\"b\", 0, \"n\", \"a@b.com\", \"p\", 0, 0, 0, 0, 1, \"8\"]]]");
}
@@ -1189,11 +1193,12 @@ TEST_F(GaiaCookieManagerServiceTest, ListAccountsFindsSignedOutAccounts) {
ASSERT_FALSE(helper.ListAccounts(&list_accounts, &signed_out_accounts));
- SimulateListAccountsSuccess(&helper,
+ SimulateListAccountsSuccess(
+ &helper,
"[\"f\","
"[[\"b\", 0, \"n\", \"a@b.com\", \"p\", 0, 0, 0, 0, 1, \"8\"],"
" [\"b\", 0, \"n\", \"c@d.com\", \"p\", 0, 0, 0, 0, 1, \"9\","
- "null,null,null,1]]]");
+ "null,null,null,1]]]");
}
TEST_F(GaiaCookieManagerServiceTest, ListAccountsAcceptsNull) {
@@ -1202,11 +1207,12 @@ TEST_F(GaiaCookieManagerServiceTest, ListAccountsAcceptsNull) {
ASSERT_FALSE(helper.ListAccounts(nullptr, nullptr));
- SimulateListAccountsSuccess(&helper,
+ SimulateListAccountsSuccess(
+ &helper,
"[\"f\","
"[[\"b\", 0, \"n\", \"a@b.com\", \"p\", 0, 0, 0, 0, 1, \"8\"],"
" [\"b\", 0, \"n\", \"c@d.com\", \"p\", 0, 0, 0, 0, 1, \"9\","
- "null,null,null,1]]]");
+ "null,null,null,1]]]");
std::vector<gaia::ListedAccount> signed_out_accounts;
ASSERT_TRUE(helper.ListAccounts(nullptr, &signed_out_accounts));
diff --git a/chromium/components/signin/core/browser/list_accounts_test_utils.cc b/chromium/components/signin/core/browser/list_accounts_test_utils.cc
new file mode 100644
index 00000000000..a8a41b2e2e7
--- /dev/null
+++ b/chromium/components/signin/core/browser/list_accounts_test_utils.cc
@@ -0,0 +1,93 @@
+// Copyright 2019 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 "components/signin/core/browser/list_accounts_test_utils.h"
+
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "services/network/test/test_url_loader_factory.h"
+
+namespace signin {
+
+using network::TestURLLoaderFactory;
+
+void SetListAccountsResponseHttpNotFound(
+ TestURLLoaderFactory* test_url_loader_factory) {
+ test_url_loader_factory->AddResponse(
+ GaiaUrls::GetInstance()
+ ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
+ .spec(),
+ /*content=*/"", net::HTTP_NOT_FOUND);
+}
+
+void SetListAccountsResponseWebLoginRequired(
+ TestURLLoaderFactory* test_url_loader_factory) {
+ test_url_loader_factory->AddResponse(
+ GaiaUrls::GetInstance()
+ ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
+ .spec(),
+ "Info=WebLoginRequired");
+}
+
+void SetListAccountsResponseWithParams(
+ const std::vector<CookieParams>& params,
+ TestURLLoaderFactory* test_url_loader_factory) {
+ std::vector<std::string> response_body;
+ for (const auto& param : params) {
+ std::string response_part = base::StringPrintf(
+ "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"%s\"",
+ param.email.c_str(), param.valid ? 1 : 0, param.gaia_id.c_str());
+ if (param.signed_out || !param.verified) {
+ response_part +=
+ base::StringPrintf(", null, null, null, %d, %d",
+ param.signed_out ? 1 : 0, param.verified ? 1 : 0);
+ }
+ response_part += "]";
+ response_body.push_back(response_part);
+ }
+
+ test_url_loader_factory->AddResponse(
+ GaiaUrls::GetInstance()
+ ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
+ .spec(),
+ std::string("[\"f\", [") + base::JoinString(response_body, ", ") + "]]");
+}
+
+void SetListAccountsResponseNoAccounts(
+ TestURLLoaderFactory* test_url_loader_factory) {
+ SetListAccountsResponseWithParams({}, test_url_loader_factory);
+}
+
+void SetListAccountsResponseOneAccount(
+ const std::string& email,
+ const std::string& gaia_id,
+ TestURLLoaderFactory* test_url_loader_factory) {
+ CookieParams params = {email, gaia_id, /*valid=*/true,
+ /*signed_out=*/false, /*verified=*/true};
+ SetListAccountsResponseWithParams({params}, test_url_loader_factory);
+}
+
+void SetListAccountsResponseOneAccountWithParams(
+ const CookieParams& params,
+ TestURLLoaderFactory* test_url_loader_factory) {
+ SetListAccountsResponseWithParams({params}, test_url_loader_factory);
+}
+
+void SetListAccountsResponseTwoAccounts(
+ const std::string& email1,
+ const std::string& gaia_id1,
+ const std::string& email2,
+ const std::string& gaia_id2,
+ TestURLLoaderFactory* test_url_loader_factory) {
+ SetListAccountsResponseWithParams(
+ {{email1, gaia_id1, /*valid=*/true, /*signed_out=*/false,
+ /*verified=*/true},
+ {email2, gaia_id2, /*valid=*/true, /*signed_out=*/false,
+ /*verified=*/true}},
+ test_url_loader_factory);
+}
+
+} // namespace signin
diff --git a/chromium/components/signin/core/browser/list_accounts_test_utils.h b/chromium/components/signin/core/browser/list_accounts_test_utils.h
new file mode 100644
index 00000000000..9a5d897f0df
--- /dev/null
+++ b/chromium/components/signin/core/browser/list_accounts_test_utils.h
@@ -0,0 +1,67 @@
+// Copyright 2019 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 COMPONENTS_SIGNIN_CORE_BROWSER_LIST_ACCOUNTS_TEST_UTILS_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_LIST_ACCOUNTS_TEST_UTILS_H_
+
+#include <string>
+#include <vector>
+
+namespace network {
+class TestURLLoaderFactory;
+} // namespace network
+
+namespace signin {
+
+// Parameters for the fake ListAccounts response.
+struct CookieParams {
+ std::string email;
+ std::string gaia_id;
+ bool valid;
+ bool signed_out;
+ bool verified;
+};
+
+// Make ListAccounts call return NotFound.
+void SetListAccountsResponseHttpNotFound(
+ network::TestURLLoaderFactory* test_url_loader_factory);
+
+// Make ListAccounts call return Info=WebLoginRequired.
+void SetListAccountsResponseWebLoginRequired(
+ network::TestURLLoaderFactory* test_url_loader_factory);
+
+// Make ListAccounts return a list of accounts based on the provided |params|.
+void SetListAccountsResponseWithParams(
+ const std::vector<CookieParams>& params,
+ network::TestURLLoaderFactory* test_url_loader_factory);
+
+// Helper methods, equivalent to calling
+// SetListAccountsResponseWithParams().
+
+// Make ListAccounts return no accounts.
+void SetListAccountsResponseNoAccounts(
+ network::TestURLLoaderFactory* test_url_loader_factory);
+
+// Make ListAccounts return one account with the provided |email| and
+// |gaia_id|.
+void SetListAccountsResponseOneAccount(
+ const std::string& email,
+ const std::string& gaia_id,
+ network::TestURLLoaderFactory* test_url_loader_factory);
+
+// Make ListAccounts return one account based on the provided |params|.
+void SetListAccountsResponseOneAccountWithParams(
+ const CookieParams& params,
+ network::TestURLLoaderFactory* test_url_loader_factory);
+
+// Make ListAccounts return two accounts with the provided emails and gaia_ids.
+void SetListAccountsResponseTwoAccounts(
+ const std::string& email1,
+ const std::string& gaia_id1,
+ const std::string& email2,
+ const std::string& gaia_id2,
+ network::TestURLLoaderFactory* test_url_loader_factory);
+
+} // namespace signin
+
+#endif // COMPONENTS_SIGNIN_CORE_BROWSER_LIST_ACCOUNTS_TEST_UTILS_H_
diff --git a/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h b/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h
index da8044614ec..05f9f72069a 100644
--- a/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h
+++ b/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h
@@ -5,6 +5,9 @@
#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_MIRROR_ACCOUNT_RECONCILOR_DELEGATE_H_
#define COMPONENTS_SIGNIN_CORE_BROWSER_MIRROR_ACCOUNT_RECONCILOR_DELEGATE_H_
+#include <string>
+#include <vector>
+
#include "base/macros.h"
#include "components/signin/core/browser/account_reconcilor_delegate.h"
#include "services/identity/public/cpp/identity_manager.h"
@@ -16,12 +19,18 @@ class MirrorAccountReconcilorDelegate
: public AccountReconcilorDelegate,
public identity::IdentityManager::Observer {
public:
- MirrorAccountReconcilorDelegate(identity::IdentityManager* identity_manager);
+ explicit MirrorAccountReconcilorDelegate(
+ identity::IdentityManager* identity_manager);
~MirrorAccountReconcilorDelegate() override;
- private:
+ protected:
// AccountReconcilorDelegate:
+ // TODO(sinhak): Make this private after deleting
+ // |ChromeOSAccountReconcilorDelegate|.
bool IsReconcileEnabled() const override;
+
+ private:
+ // AccountReconcilorDelegate:
bool IsAccountConsistencyEnforced() const override;
gaia::GaiaSource GetGaiaApiSource() const override;
bool ShouldAbortReconcileIfPrimaryHasError() const override;
diff --git a/chromium/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate.cc b/chromium/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate.cc
new file mode 100644
index 00000000000..b191706de13
--- /dev/null
+++ b/chromium/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate.cc
@@ -0,0 +1,944 @@
+// Copyright 2015 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 "components/signin/core/browser/mutable_profile_oauth2_token_service_delegate.h"
+
+#include <stddef.h>
+
+#include <map>
+#include <string>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/metrics/histogram_macros.h"
+#include "build/build_config.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/signin/core/browser/account_info.h"
+#include "components/signin/core/browser/signin_client.h"
+#include "components/signin/core/browser/signin_metrics.h"
+#include "components/signin/core/browser/signin_pref_names.h"
+#include "components/signin/core/browser/webdata/token_web_data.h"
+#include "components/webdata/common/web_data_service_base.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
+#include "google_apis/gaia/gaia_auth_util.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher_immediate_error.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+namespace {
+
+const char kAccountIdPrefix[] = "AccountId-";
+const size_t kAccountIdPrefixLength = 10;
+
+// Used to record token state transitions in histograms.
+// Do not change existing values, new values can only be added at the end.
+enum class TokenStateTransition {
+ // Update events.
+ kNoneToInvalid = 0,
+ kNoneToRegular,
+ kInvalidToRegular,
+ kRegularToInvalid,
+ kRegularToRegular,
+
+ // Revocation events.
+ kInvalidToNone,
+ kRegularToNone,
+
+ // Load events.
+ kLoadRegular,
+ kLoadInvalid,
+ kLoadInvalidNoTokenForPrimaryAccount,
+
+ kCount
+};
+
+// Enum for the Signin.LoadTokenFromDB histogram.
+// Do not modify, or add or delete other than directly before
+// NUM_LOAD_TOKEN_FROM_DB_STATUS.
+enum class LoadTokenFromDBStatus {
+ // Token was loaded.
+ TOKEN_LOADED = 0,
+ // Token was revoked as part of Dice migration.
+ TOKEN_REVOKED_DICE_MIGRATION = 1,
+ // Token was revoked because it is a secondary account and account consistency
+ // is disabled.
+ TOKEN_REVOKED_SECONDARY_ACCOUNT = 2,
+ // Token was revoked on load due to cookie settings.
+ TOKEN_REVOKED_ON_LOAD = 3,
+
+ NUM_LOAD_TOKEN_FROM_DB_STATUS
+};
+
+// Used to record events related to token revocation requests in histograms.
+// Do not change existing values, new values can only be added at the end.
+enum class TokenRevocationRequestProgress {
+ // The request was created.
+ kRequestCreated = 0,
+ // The request was sent over the network.
+ kRequestStarted = 1,
+ // The network request completed with a failure.
+ kRequestFailed = 2,
+ // The network request completed with a success.
+ kRequestSucceeded = 3,
+
+ kMaxValue = kRequestSucceeded
+};
+
+// Adds a sample to the TokenStateTransition histogram. Encapsuled in a function
+// to reduce executable size, because histogram macros may generate a lot of
+// code.
+void RecordTokenStateTransition(TokenStateTransition transition) {
+ UMA_HISTOGRAM_ENUMERATION("Signin.TokenStateTransition", transition,
+ TokenStateTransition::kCount);
+}
+
+// Adds a sample to the TokenRevocationRequestProgress histogram. Encapsuled in
+// a function to reduce executable size, because histogram macros may generate a
+// lot of code.
+void RecordRefreshTokenRevocationRequestEvent(
+ TokenRevocationRequestProgress event) {
+ UMA_HISTOGRAM_ENUMERATION("Signin.RefreshTokenRevocationRequestProgress",
+ event);
+}
+
+// Record metrics when a token was updated.
+void RecordTokenChanged(const std::string& existing_token,
+ const std::string& new_token) {
+ DCHECK_NE(existing_token, new_token);
+ DCHECK(!new_token.empty());
+ TokenStateTransition transition = TokenStateTransition::kCount;
+ if (existing_token.empty()) {
+ transition = (new_token == OAuth2TokenServiceDelegate::kInvalidRefreshToken)
+ ? TokenStateTransition::kNoneToInvalid
+ : TokenStateTransition::kNoneToRegular;
+ } else if (existing_token ==
+ OAuth2TokenServiceDelegate::kInvalidRefreshToken) {
+ transition = TokenStateTransition::kInvalidToRegular;
+ } else {
+ // Existing token is a regular token.
+ transition = (new_token == OAuth2TokenServiceDelegate::kInvalidRefreshToken)
+ ? TokenStateTransition::kRegularToInvalid
+ : TokenStateTransition::kRegularToRegular;
+ }
+ DCHECK_NE(TokenStateTransition::kCount, transition);
+ RecordTokenStateTransition(transition);
+}
+
+// Record metrics when a token was loaded.
+void RecordTokenLoaded(const std::string& token) {
+ RecordTokenStateTransition(
+ (token == OAuth2TokenServiceDelegate::kInvalidRefreshToken)
+ ? TokenStateTransition::kLoadInvalid
+ : TokenStateTransition::kLoadRegular);
+}
+
+// Record metrics when a token was revoked.
+void RecordTokenRevoked(const std::string& token) {
+ RecordTokenStateTransition(
+ (token == OAuth2TokenServiceDelegate::kInvalidRefreshToken)
+ ? TokenStateTransition::kInvalidToNone
+ : TokenStateTransition::kRegularToNone);
+}
+
+std::string ApplyAccountIdPrefix(const std::string& account_id) {
+ return kAccountIdPrefix + account_id;
+}
+
+bool IsLegacyRefreshTokenId(const std::string& service_id) {
+ return service_id == GaiaConstants::kGaiaOAuth2LoginRefreshToken;
+}
+
+bool IsLegacyServiceId(const std::string& account_id) {
+ return account_id.compare(0u, kAccountIdPrefixLength, kAccountIdPrefix) != 0;
+}
+
+std::string RemoveAccountIdPrefix(const std::string& prefixed_account_id) {
+ return prefixed_account_id.substr(kAccountIdPrefixLength);
+}
+
+OAuth2TokenServiceDelegate::LoadCredentialsState
+LoadCredentialsStateFromTokenResult(TokenServiceTable::Result token_result) {
+ switch (token_result) {
+ case TokenServiceTable::TOKEN_DB_RESULT_SQL_INVALID_STATEMENT:
+ case TokenServiceTable::TOKEN_DB_RESULT_BAD_ENTRY:
+ return OAuth2TokenServiceDelegate::
+ LOAD_CREDENTIALS_FINISHED_WITH_DB_ERRORS;
+ case TokenServiceTable::TOKEN_DB_RESULT_DECRYPT_ERROR:
+ return OAuth2TokenServiceDelegate::
+ LOAD_CREDENTIALS_FINISHED_WITH_DECRYPT_ERRORS;
+ case TokenServiceTable::TOKEN_DB_RESULT_SUCCESS:
+ return OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS;
+ }
+ NOTREACHED();
+ return OAuth2TokenServiceDelegate::
+ LOAD_CREDENTIALS_FINISHED_WITH_UNKNOWN_ERRORS;
+}
+
+// Returns whether the token service should be migrated to Dice.
+// Migration can happen if the following conditions are met:
+// - Token service Dice migration is not already done,
+// - AccountTrackerService migration is done,
+// - All accounts in the AccountTrackerService are valid,
+// - Account consistency is DiceMigration or greater.
+// TODO(droger): Remove this code once Dice is fully enabled.
+bool ShouldMigrateToDice(signin::AccountConsistencyMethod account_consistency,
+ PrefService* prefs,
+ AccountTrackerService* account_tracker,
+ const std::map<std::string, std::string>& db_tokens) {
+ AccountTrackerService::AccountIdMigrationState migration_state =
+ account_tracker->GetMigrationState();
+ if ((account_consistency == signin::AccountConsistencyMethod::kMirror) ||
+ !signin::DiceMethodGreaterOrEqual(
+ account_consistency,
+ signin::AccountConsistencyMethod::kDiceMigration) ||
+ (migration_state != AccountTrackerService::MIGRATION_DONE) ||
+ prefs->GetBoolean(prefs::kTokenServiceDiceCompatible)) {
+ return false;
+ }
+
+ // Do not migrate if some accounts are not valid.
+ for (auto iter = db_tokens.begin(); iter != db_tokens.end(); ++iter) {
+ const std::string& prefixed_account_id = iter->first;
+ std::string account_id = RemoveAccountIdPrefix(prefixed_account_id);
+ AccountInfo account_info = account_tracker->GetAccountInfo(account_id);
+ if (!account_info.IsValid()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+// This class sends a request to GAIA to revoke the given refresh token from
+// the server. This is a best effort attempt only. This class deletes itself
+// when done successfully or otherwise.
+class MutableProfileOAuth2TokenServiceDelegate::RevokeServerRefreshToken
+ : public GaiaAuthConsumer {
+ public:
+ RevokeServerRefreshToken(
+ MutableProfileOAuth2TokenServiceDelegate* token_service_delegate,
+ SigninClient* client,
+ const std::string& refresh_token,
+ int attempt);
+ ~RevokeServerRefreshToken() override;
+
+ private:
+ // Starts the network request.
+ void Start();
+ // Returns true if the request should be retried.
+ bool ShouldRetry(GaiaAuthConsumer::TokenRevocationStatus status);
+ // GaiaAuthConsumer overrides:
+ void OnOAuth2RevokeTokenCompleted(
+ GaiaAuthConsumer::TokenRevocationStatus status) override;
+
+ MutableProfileOAuth2TokenServiceDelegate* token_service_delegate_;
+ GaiaAuthFetcher fetcher_;
+ std::string refresh_token_;
+ int attempt_;
+ base::WeakPtrFactory<RevokeServerRefreshToken> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(RevokeServerRefreshToken);
+};
+
+MutableProfileOAuth2TokenServiceDelegate::RevokeServerRefreshToken::
+ RevokeServerRefreshToken(
+ MutableProfileOAuth2TokenServiceDelegate* token_service_delegate,
+ SigninClient* client,
+ const std::string& refresh_token,
+ int attempt)
+ : token_service_delegate_(token_service_delegate),
+ fetcher_(this,
+ gaia::GaiaSource::kChrome,
+ token_service_delegate_->GetURLLoaderFactory()),
+ refresh_token_(refresh_token),
+ attempt_(attempt),
+ weak_ptr_factory_(this) {
+ RecordRefreshTokenRevocationRequestEvent(
+ TokenRevocationRequestProgress::kRequestCreated);
+ client->DelayNetworkCall(
+ base::BindRepeating(&MutableProfileOAuth2TokenServiceDelegate::
+ RevokeServerRefreshToken::Start,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::RevokeServerRefreshToken::
+ Start() {
+ RecordRefreshTokenRevocationRequestEvent(
+ TokenRevocationRequestProgress::kRequestStarted);
+ fetcher_.StartRevokeOAuth2Token(refresh_token_);
+}
+
+MutableProfileOAuth2TokenServiceDelegate::RevokeServerRefreshToken::
+ ~RevokeServerRefreshToken() {}
+
+bool MutableProfileOAuth2TokenServiceDelegate::RevokeServerRefreshToken::
+ ShouldRetry(GaiaAuthConsumer::TokenRevocationStatus status) {
+ // Token revocation can be retried up to 3 times.
+ if (attempt_ >= 2)
+ return false;
+
+ switch (status) {
+ case GaiaAuthConsumer::TokenRevocationStatus::kServerError:
+ case GaiaAuthConsumer::TokenRevocationStatus::kConnectionFailed:
+ case GaiaAuthConsumer::TokenRevocationStatus::kConnectionTimeout:
+ case GaiaAuthConsumer::TokenRevocationStatus::kConnectionCanceled:
+ return true;
+ case GaiaAuthConsumer::TokenRevocationStatus::kSuccess:
+ case GaiaAuthConsumer::TokenRevocationStatus::kInvalidToken:
+ case GaiaAuthConsumer::TokenRevocationStatus::kInvalidRequest:
+ case GaiaAuthConsumer::TokenRevocationStatus::kUnknownError:
+ return false;
+ }
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::RevokeServerRefreshToken::
+ OnOAuth2RevokeTokenCompleted(
+ GaiaAuthConsumer::TokenRevocationStatus status) {
+ UMA_HISTOGRAM_ENUMERATION("Signin.RefreshTokenRevocationStatus", status);
+ if (ShouldRetry(status)) {
+ token_service_delegate_->server_revokes_.push_back(
+ std::make_unique<RevokeServerRefreshToken>(
+ token_service_delegate_, token_service_delegate_->client_,
+ refresh_token_, attempt_ + 1));
+ } else {
+ RecordRefreshTokenRevocationRequestEvent(
+ (status == GaiaAuthConsumer::TokenRevocationStatus::kSuccess)
+ ? TokenRevocationRequestProgress::kRequestSucceeded
+ : TokenRevocationRequestProgress::kRequestFailed);
+ UMA_HISTOGRAM_ENUMERATION("Signin.RefreshTokenRevocationCompleted", status);
+ }
+ // |this| pointer will be deleted when removed from the vector, so don't
+ // access any members after call to erase().
+ token_service_delegate_->server_revokes_.erase(std::find_if(
+ token_service_delegate_->server_revokes_.begin(),
+ token_service_delegate_->server_revokes_.end(),
+ [this](const std::unique_ptr<MutableProfileOAuth2TokenServiceDelegate::
+ RevokeServerRefreshToken>& item) {
+ return item.get() == this;
+ }));
+}
+
+MutableProfileOAuth2TokenServiceDelegate::
+ MutableProfileOAuth2TokenServiceDelegate(
+ SigninClient* client,
+ AccountTrackerService* account_tracker_service,
+ network::NetworkConnectionTracker* network_connection_tracker,
+ scoped_refptr<TokenWebData> token_web_data,
+ signin::AccountConsistencyMethod account_consistency,
+ bool revoke_all_tokens_on_load,
+ bool can_revoke_credentials,
+ FixRequestErrorCallback fix_request_error_callback)
+ : web_data_service_request_(0),
+ backoff_entry_(&backoff_policy_),
+ backoff_error_(GoogleServiceAuthError::NONE),
+ client_(client),
+ account_tracker_service_(account_tracker_service),
+ network_connection_tracker_(network_connection_tracker),
+ token_web_data_(token_web_data),
+ account_consistency_(account_consistency),
+ revoke_all_tokens_on_load_(revoke_all_tokens_on_load),
+ can_revoke_credentials_(can_revoke_credentials),
+ fix_request_error_callback_(fix_request_error_callback) {
+ VLOG(1) << "MutablePO2TS::MutablePO2TS";
+ DCHECK(client);
+ DCHECK(account_tracker_service_);
+ DCHECK(network_connection_tracker_);
+ // It's okay to fill the backoff policy after being used in construction.
+ backoff_policy_.num_errors_to_ignore = 0;
+ backoff_policy_.initial_delay_ms = 1000;
+ backoff_policy_.multiply_factor = 2.0;
+ backoff_policy_.jitter_factor = 0.2;
+ backoff_policy_.maximum_backoff_ms = 15 * 60 * 1000;
+ backoff_policy_.entry_lifetime_ms = -1;
+ backoff_policy_.always_use_initial_delay = false;
+ network_connection_tracker_->AddNetworkConnectionObserver(this);
+}
+
+MutableProfileOAuth2TokenServiceDelegate::
+ ~MutableProfileOAuth2TokenServiceDelegate() {
+ VLOG(1) << "MutablePO2TS::~MutablePO2TS";
+ DCHECK(server_revokes_.empty());
+ network_connection_tracker_->RemoveNetworkConnectionObserver(this);
+}
+
+// static
+void MutableProfileOAuth2TokenServiceDelegate::RegisterProfilePrefs(
+ PrefRegistrySimple* registry) {
+ registry->RegisterBooleanPref(prefs::kTokenServiceDiceCompatible, false);
+}
+
+OAuth2AccessTokenFetcher*
+MutableProfileOAuth2TokenServiceDelegate::CreateAccessTokenFetcher(
+ const std::string& account_id,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ OAuth2AccessTokenConsumer* consumer) {
+ ValidateAccountId(account_id);
+ // check whether the account has persistent error.
+ if (refresh_tokens_[account_id].last_auth_error.IsPersistentError()) {
+ VLOG(1) << "Request for token has been rejected due to persistent error #"
+ << refresh_tokens_[account_id].last_auth_error.state();
+ return new OAuth2AccessTokenFetcherImmediateError(
+ consumer, refresh_tokens_[account_id].last_auth_error);
+ }
+ if (backoff_entry_.ShouldRejectRequest()) {
+ VLOG(1) << "Request for token has been rejected due to backoff rules from"
+ << " previous error #" << backoff_error_.state();
+ return new OAuth2AccessTokenFetcherImmediateError(consumer, backoff_error_);
+ }
+ std::string refresh_token = GetRefreshToken(account_id);
+ DCHECK(!refresh_token.empty());
+ return new OAuth2AccessTokenFetcherImpl(consumer, url_loader_factory,
+ refresh_token);
+}
+
+GoogleServiceAuthError MutableProfileOAuth2TokenServiceDelegate::GetAuthError(
+ const std::string& account_id) const {
+ auto it = refresh_tokens_.find(account_id);
+ return (it == refresh_tokens_.end()) ? GoogleServiceAuthError::AuthErrorNone()
+ : it->second.last_auth_error;
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::UpdateAuthError(
+ const std::string& account_id,
+ const GoogleServiceAuthError& error) {
+ VLOG(1) << "MutablePO2TS::UpdateAuthError. Error: " << error.state()
+ << " account_id=" << account_id;
+ backoff_entry_.InformOfRequest(!error.IsTransientError());
+ ValidateAccountId(account_id);
+
+ // Do not report connection errors as these are not actually auth errors.
+ // We also want to avoid masking a "real" auth error just because we
+ // subsequently get a transient network error. We do keep it around though
+ // to report for future requests being denied for "backoff" reasons.
+ if (error.IsTransientError()) {
+ backoff_error_ = error;
+ return;
+ }
+
+ if (refresh_tokens_.count(account_id) == 0) {
+ // This could happen if the preferences have been corrupted (see
+ // http://crbug.com/321370). In a Debug build that would be a bug, but in a
+ // Release build we want to deal with it gracefully.
+ NOTREACHED();
+ return;
+ }
+
+ AccountStatus* status = &refresh_tokens_[account_id];
+ if (error != status->last_auth_error) {
+ status->last_auth_error = error;
+ FireAuthErrorChanged(account_id, error);
+ }
+}
+
+std::string MutableProfileOAuth2TokenServiceDelegate::GetTokenForMultilogin(
+ const std::string& account_id) const {
+ auto iter = refresh_tokens_.find(account_id);
+ if (iter == refresh_tokens_.end() ||
+ iter->second.last_auth_error != GoogleServiceAuthError::AuthErrorNone()) {
+ return std::string();
+ }
+ const std::string& refresh_token = iter->second.refresh_token;
+ DCHECK(!refresh_token.empty());
+ return refresh_token;
+}
+
+bool MutableProfileOAuth2TokenServiceDelegate::RefreshTokenIsAvailable(
+ const std::string& account_id) const {
+ VLOG(1) << "MutablePO2TS::RefreshTokenIsAvailable";
+ return !GetRefreshToken(account_id).empty();
+}
+
+std::string MutableProfileOAuth2TokenServiceDelegate::GetRefreshToken(
+ const std::string& account_id) const {
+ auto iter = refresh_tokens_.find(account_id);
+ if (iter != refresh_tokens_.end()) {
+ const std::string refresh_token = iter->second.refresh_token;
+ DCHECK(!refresh_token.empty());
+ return refresh_token;
+ }
+ return std::string();
+}
+
+std::string MutableProfileOAuth2TokenServiceDelegate::GetRefreshTokenForTest(
+ const std::string& account_id) const {
+ return GetRefreshToken(account_id);
+}
+
+std::vector<std::string>
+MutableProfileOAuth2TokenServiceDelegate::GetAccounts() {
+ std::vector<std::string> account_ids;
+ for (auto& token : refresh_tokens_) {
+ account_ids.push_back(token.first);
+ }
+ return account_ids;
+}
+
+scoped_refptr<network::SharedURLLoaderFactory>
+MutableProfileOAuth2TokenServiceDelegate::GetURLLoaderFactory() const {
+ return client_->GetURLLoaderFactory();
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::InvalidateTokenForMultilogin(
+ const std::string& failed_account) {
+ UpdateAuthError(
+ failed_account,
+ GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::LoadCredentials(
+ const std::string& primary_account_id) {
+ if (load_credentials_state() == LOAD_CREDENTIALS_IN_PROGRESS) {
+ VLOG(1) << "Load credentials operation already in progress";
+ return;
+ }
+
+ set_load_credentials_state(LOAD_CREDENTIALS_IN_PROGRESS);
+
+#if defined(OS_CHROMEOS)
+ // ChromeOS OOBE loads credentials without a primary account and expects this
+ // to be a no-op. See htttp://crbug.com/891818
+ if (primary_account_id.empty()) {
+ set_load_credentials_state(LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS);
+ FinishLoadingCredentials();
+ return;
+ }
+#endif
+
+ if (!primary_account_id.empty())
+ ValidateAccountId(primary_account_id);
+ DCHECK(loading_primary_account_id_.empty());
+ DCHECK_EQ(0, web_data_service_request_);
+
+ refresh_tokens_.clear();
+
+ if (!token_web_data_) {
+ // This case only exists in unit tests that do not care about loading
+ // credentials.
+ set_load_credentials_state(LOAD_CREDENTIALS_FINISHED_WITH_UNKNOWN_ERRORS);
+ FinishLoadingCredentials();
+ return;
+ }
+
+ // If |account_id| is an email address, then canonicalize it. This is needed
+ // to support legacy account IDs, and will not be needed after switching to
+ // gaia IDs.
+ if (primary_account_id.find('@') != std::string::npos) {
+ loading_primary_account_id_ = gaia::CanonicalizeEmail(primary_account_id);
+ } else {
+ loading_primary_account_id_ = primary_account_id;
+ }
+
+ web_data_service_request_ = token_web_data_->GetAllTokens(this);
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::OnWebDataServiceRequestDone(
+ WebDataServiceBase::Handle handle,
+ std::unique_ptr<WDTypedResult> result) {
+ VLOG(1) << "MutablePO2TS::OnWebDataServiceRequestDone. Result type: "
+ << (result.get() == nullptr ? -1
+ : static_cast<int>(result->GetType()));
+
+ DCHECK_EQ(web_data_service_request_, handle);
+ web_data_service_request_ = 0;
+
+ if (result) {
+ DCHECK(result->GetType() == TOKEN_RESULT);
+ const WDResult<TokenResult>* token_result =
+ static_cast<const WDResult<TokenResult>*>(result.get());
+ LoadAllCredentialsIntoMemory(token_result->GetValue().tokens);
+ set_load_credentials_state(LoadCredentialsStateFromTokenResult(
+ token_result->GetValue().db_result));
+ } else {
+ set_load_credentials_state(LOAD_CREDENTIALS_FINISHED_WITH_UNKNOWN_ERRORS);
+ }
+
+ // Make sure that we have an entry for |loading_primary_account_id_| in the
+ // map. The entry could be missing if there is a corruption in the token DB
+ // while this profile is connected to an account.
+ if (!loading_primary_account_id_.empty() &&
+ refresh_tokens_.count(loading_primary_account_id_) == 0) {
+ if (load_credentials_state() == LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS) {
+ set_load_credentials_state(
+ LOAD_CREDENTIALS_FINISHED_WITH_NO_TOKEN_FOR_PRIMARY_ACCOUNT);
+ }
+ AddAccountStatus(loading_primary_account_id_, kInvalidRefreshToken,
+ GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_MISSING));
+ RecordTokenStateTransition(
+ TokenStateTransition::kLoadInvalidNoTokenForPrimaryAccount);
+ FireRefreshTokenAvailable(loading_primary_account_id_);
+ }
+
+#ifndef NDEBUG
+ for (auto& token : refresh_tokens_) {
+ DCHECK(RefreshTokenIsAvailable(token.first))
+ << "Missing token for " << token.first;
+ }
+#endif
+
+ loading_primary_account_id_.clear();
+ FinishLoadingCredentials();
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::LoadAllCredentialsIntoMemory(
+ const std::map<std::string, std::string>& db_tokens) {
+ std::string old_login_token;
+ bool migrate_to_dice =
+ ShouldMigrateToDice(account_consistency_, client_->GetPrefs(),
+ account_tracker_service_, db_tokens);
+
+ {
+ ScopedBatchChange batch(this);
+
+ VLOG(1) << "MutablePO2TS::LoadAllCredentialsIntoMemory; "
+ << db_tokens.size() << " Credential(s).";
+ AccountTrackerService::AccountIdMigrationState migration_state =
+ account_tracker_service_->GetMigrationState();
+ for (auto iter = db_tokens.begin(); iter != db_tokens.end(); ++iter) {
+ std::string prefixed_account_id = iter->first;
+ std::string refresh_token = iter->second;
+
+ if (IsLegacyRefreshTokenId(prefixed_account_id) && !refresh_token.empty())
+ old_login_token = refresh_token;
+
+ if (IsLegacyServiceId(prefixed_account_id)) {
+ if (token_web_data_) {
+ VLOG(1) << "MutablePO2TS remove legacy refresh token for account id "
+ << prefixed_account_id;
+ token_web_data_->RemoveTokenForService(prefixed_account_id);
+ }
+ } else {
+ DCHECK(!refresh_token.empty());
+ std::string account_id = RemoveAccountIdPrefix(prefixed_account_id);
+
+ switch (migration_state) {
+ case AccountTrackerService::MIGRATION_IN_PROGRESS: {
+ // Migrate to gaia-ids.
+ AccountInfo account_info =
+ account_tracker_service_->FindAccountInfoByEmail(account_id);
+ // |account_info.gaia| could be empty if |account_id| is already
+ // gaia id. This could happen if the chrome was closed in the middle
+ // of migration.
+ if (!account_info.gaia.empty()) {
+ ClearPersistedCredentials(account_id);
+ PersistCredentials(account_info.gaia, refresh_token);
+ account_id = account_info.gaia;
+ }
+
+ // Skip duplicate accounts, this could happen if migration was
+ // crashed in the middle.
+ if (refresh_tokens_.count(account_id) != 0)
+ continue;
+ break;
+ }
+ case AccountTrackerService::MIGRATION_NOT_STARTED:
+ // If the account_id is an email address, then canonicalize it. This
+ // is to support legacy account_ids, and will not be needed after
+ // switching to gaia-ids.
+ if (account_id.find('@') != std::string::npos) {
+ // If the canonical account id is not the same as the loaded
+ // account id, make sure not to overwrite a refresh token from
+ // a canonical version. If no canonical version was loaded, then
+ // re-persist this refresh token with the canonical account id.
+ std::string canon_account_id =
+ gaia::CanonicalizeEmail(account_id);
+ if (canon_account_id != account_id) {
+ ClearPersistedCredentials(account_id);
+ if (db_tokens.count(ApplyAccountIdPrefix(canon_account_id)) ==
+ 0)
+ PersistCredentials(canon_account_id, refresh_token);
+ }
+ account_id = canon_account_id;
+ }
+ break;
+ case AccountTrackerService::MIGRATION_DONE:
+ DCHECK_EQ(std::string::npos, account_id.find('@'));
+ break;
+ case AccountTrackerService::NUM_MIGRATION_STATES:
+ NOTREACHED();
+ break;
+ }
+
+ // Only load secondary accounts when account consistency is enabled.
+ bool load_account =
+ (account_id == loading_primary_account_id_) ||
+ (account_consistency_ ==
+ signin::AccountConsistencyMethod::kMirror) ||
+ signin::DiceMethodGreaterOrEqual(
+ account_consistency_,
+ signin::AccountConsistencyMethod::kDiceMigration);
+ LoadTokenFromDBStatus load_token_status =
+ load_account
+ ? LoadTokenFromDBStatus::TOKEN_LOADED
+ : LoadTokenFromDBStatus::TOKEN_REVOKED_SECONDARY_ACCOUNT;
+
+ if (migrate_to_dice) {
+ // Revoke old hosted domain accounts as part of Dice migration.
+ AccountInfo account_info =
+ account_tracker_service_->GetAccountInfo(account_id);
+ DCHECK(account_info.IsValid());
+ if (account_info.hosted_domain != kNoHostedDomainFound) {
+ load_account = false;
+ load_token_status =
+ LoadTokenFromDBStatus::TOKEN_REVOKED_DICE_MIGRATION;
+ }
+ }
+
+ if (load_account && revoke_all_tokens_on_load_) {
+ if (account_id == loading_primary_account_id_) {
+ RevokeCredentialsOnServer(refresh_token);
+ refresh_token = kInvalidRefreshToken;
+ PersistCredentials(account_id, refresh_token);
+ } else {
+ load_account = false;
+ }
+ load_token_status = LoadTokenFromDBStatus::TOKEN_REVOKED_ON_LOAD;
+ }
+
+ UMA_HISTOGRAM_ENUMERATION(
+ "Signin.LoadTokenFromDB", load_token_status,
+ LoadTokenFromDBStatus::NUM_LOAD_TOKEN_FROM_DB_STATUS);
+
+ if (load_account) {
+ RecordTokenLoaded(refresh_token);
+ UpdateCredentialsInMemory(account_id, refresh_token);
+ FireRefreshTokenAvailable(account_id);
+ } else {
+ RecordTokenRevoked(refresh_token);
+ RevokeCredentialsOnServer(refresh_token);
+ ClearPersistedCredentials(account_id);
+ FireRefreshTokenRevoked(account_id);
+ }
+ }
+ }
+
+ if (!old_login_token.empty()) {
+ DCHECK(!loading_primary_account_id_.empty());
+ if (refresh_tokens_.count(loading_primary_account_id_) == 0)
+ UpdateCredentials(loading_primary_account_id_, old_login_token);
+ }
+ }
+
+ if (migrate_to_dice)
+ client_->GetPrefs()->SetBoolean(prefs::kTokenServiceDiceCompatible, true);
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::UpdateCredentials(
+ const std::string& account_id,
+ const std::string& refresh_token) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(!account_id.empty());
+ DCHECK(!refresh_token.empty());
+
+ ValidateAccountId(account_id);
+ signin_metrics::LogSigninAddAccount();
+
+ const std::string& existing_token = GetRefreshToken(account_id);
+ if (existing_token != refresh_token) {
+ ScopedBatchChange batch(this);
+ RecordTokenChanged(existing_token, refresh_token);
+ UpdateCredentialsInMemory(account_id, refresh_token);
+ PersistCredentials(account_id, refresh_token);
+ FireRefreshTokenAvailable(account_id);
+ }
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::UpdateCredentialsInMemory(
+ const std::string& account_id,
+ const std::string& refresh_token) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(!account_id.empty());
+ DCHECK(!refresh_token.empty());
+
+ bool is_refresh_token_invalidated = refresh_token == kInvalidRefreshToken;
+ GoogleServiceAuthError error =
+ is_refresh_token_invalidated
+ ? GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_CLIENT)
+ : GoogleServiceAuthError::AuthErrorNone();
+
+ bool refresh_token_present = refresh_tokens_.count(account_id) > 0;
+ // If token present, and different from the new one, cancel its requests,
+ // and clear the entries in cache related to that account.
+ if (refresh_token_present) {
+ DCHECK_NE(refresh_token, refresh_tokens_[account_id].refresh_token);
+ VLOG(1) << "MutablePO2TS::UpdateCredentials; Refresh Token was present. "
+ << "account_id=" << account_id;
+
+ // The old refresh token must be revoked on the server only when it is
+ // invalidated.
+ //
+ // The refresh token is updated to a new valid one in case of reauth.
+ // In the reauth case the old and the new refresh tokens have the same
+ // device ID. When revoking a refresh token on the server, Gaia revokes
+ // all the refresh tokens that have the same device ID.
+ // Therefore, the old refresh token must not be revoked on the server
+ // when it is updated to a new valid one (otherwise the new refresh token
+ // would also be invalidated server-side).
+ // See http://crbug.com/865189 for more information about this regression.
+ if (is_refresh_token_invalidated)
+ RevokeCredentialsOnServer(refresh_tokens_[account_id].refresh_token);
+
+ refresh_tokens_[account_id].refresh_token = refresh_token;
+ UpdateAuthError(account_id, error);
+ } else {
+ VLOG(1) << "MutablePO2TS::UpdateCredentials; Refresh Token was absent. "
+ << "account_id=" << account_id;
+ AddAccountStatus(account_id, refresh_token, error);
+ }
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::PersistCredentials(
+ const std::string& account_id,
+ const std::string& refresh_token) {
+ DCHECK(!account_id.empty());
+ DCHECK(!refresh_token.empty());
+ if (token_web_data_) {
+ VLOG(1) << "MutablePO2TS::PersistCredentials for account_id=" << account_id;
+ token_web_data_->SetTokenForService(ApplyAccountIdPrefix(account_id),
+ refresh_token);
+ }
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::RevokeAllCredentials() {
+ if (!can_revoke_credentials_)
+ return;
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ VLOG(1) << "MutablePO2TS::RevokeAllCredentials";
+
+ ScopedBatchChange batch(this);
+ if (load_credentials_state() == LOAD_CREDENTIALS_IN_PROGRESS) {
+ VLOG(1) << "MutablePO2TS::RevokeAllCredentials before tokens are loaded.";
+ // If |RevokeAllCredentials| is called while credentials are being loaded,
+ // then the load must be cancelled and the load credentials state updated.
+ DCHECK_NE(0, web_data_service_request_);
+ CancelWebTokenFetch();
+ set_load_credentials_state(LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS);
+ FinishLoadingCredentials();
+ }
+
+ // Make a temporary copy of the account ids.
+ std::vector<std::string> accounts;
+ for (const auto& token : refresh_tokens_)
+ accounts.push_back(token.first);
+ for (const std::string& account : accounts)
+ RevokeCredentials(account);
+
+ DCHECK_EQ(0u, refresh_tokens_.size());
+
+ // Make sure all tokens are removed from storage.
+ if (token_web_data_)
+ token_web_data_->RemoveAllTokens();
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::RevokeCredentials(
+ const std::string& account_id) {
+ RevokeCredentialsImpl(account_id, /*revoke_on_server=*/true);
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::ClearPersistedCredentials(
+ const std::string& account_id) {
+ DCHECK(!account_id.empty());
+ if (token_web_data_) {
+ VLOG(1) << "MutablePO2TS::ClearPersistedCredentials for account_id="
+ << account_id;
+ token_web_data_->RemoveTokenForService(ApplyAccountIdPrefix(account_id));
+ }
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::RevokeCredentialsOnServer(
+ const std::string& refresh_token) {
+ DCHECK(!refresh_token.empty());
+
+ if (refresh_token == kInvalidRefreshToken)
+ return;
+
+ // Keep track or all server revoke requests. This way they can be deleted
+ // before the token service is shutdown and won't outlive the profile.
+ server_revokes_.push_back(std::make_unique<RevokeServerRefreshToken>(
+ this, client_, refresh_token, 0));
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::CancelWebTokenFetch() {
+ if (web_data_service_request_ != 0) {
+ DCHECK(token_web_data_);
+ token_web_data_->CancelRequest(web_data_service_request_);
+ web_data_service_request_ = 0;
+ }
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::ExtractCredentials(
+ OAuth2TokenService* to_service,
+ const std::string& account_id) {
+ static_cast<ProfileOAuth2TokenService*>(to_service)
+ ->UpdateCredentials(account_id, GetRefreshToken(account_id),
+ signin_metrics::SourceForRefreshTokenOperation::
+ kTokenService_ExtractCredentials);
+ RevokeCredentialsImpl(account_id, /*revoke_on_server=*/false);
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::Shutdown() {
+ VLOG(1) << "MutablePO2TS::Shutdown";
+ server_revokes_.clear();
+ CancelWebTokenFetch();
+ refresh_tokens_.clear();
+ OAuth2TokenServiceDelegate::Shutdown();
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::OnConnectionChanged(
+ network::mojom::ConnectionType type) {
+ // If our network has changed, reset the backoff timer so that errors caused
+ // by a previous lack of network connectivity don't prevent new requests.
+ backoff_entry_.Reset();
+}
+
+const net::BackoffEntry*
+MutableProfileOAuth2TokenServiceDelegate::BackoffEntry() const {
+ return &backoff_entry_;
+}
+
+bool MutableProfileOAuth2TokenServiceDelegate::FixRequestErrorIfPossible() {
+ return !fix_request_error_callback_.is_null()
+ ? fix_request_error_callback_.Run()
+ : false;
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::AddAccountStatus(
+ const std::string& account_id,
+ const std::string& refresh_token,
+ const GoogleServiceAuthError& error) {
+ DCHECK_EQ(0u, refresh_tokens_.count(account_id));
+ refresh_tokens_[account_id] = AccountStatus{refresh_token, error};
+ FireAuthErrorChanged(account_id, error);
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::FinishLoadingCredentials() {
+ FireRefreshTokensLoaded();
+}
+
+void MutableProfileOAuth2TokenServiceDelegate::RevokeCredentialsImpl(
+ const std::string& account_id,
+ bool revoke_on_server) {
+ ValidateAccountId(account_id);
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (refresh_tokens_.count(account_id) > 0) {
+ VLOG(1) << "MutablePO2TS::RevokeCredentials for account_id=" << account_id;
+ ScopedBatchChange batch(this);
+ const std::string& token = refresh_tokens_[account_id].refresh_token;
+ RecordTokenRevoked(token);
+ if (revoke_on_server)
+ RevokeCredentialsOnServer(token);
+ refresh_tokens_.erase(account_id);
+ ClearPersistedCredentials(account_id);
+ FireRefreshTokenRevoked(account_id);
+ }
+}
diff --git a/chromium/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate.h b/chromium/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate.h
new file mode 100644
index 00000000000..906e25a5c9e
--- /dev/null
+++ b/chromium/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate.h
@@ -0,0 +1,236 @@
+// Copyright 2015 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 COMPONENTS_SIGNIN_CORE_BROWSER_MUTABLE_PROFILE_OAUTH2_TOKEN_SERVICE_DELEGATE_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_MUTABLE_PROFILE_OAUTH2_TOKEN_SERVICE_DELEGATE_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "components/signin/core/browser/account_consistency_method.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/webdata/token_web_data.h"
+#include "components/webdata/common/web_data_service_base.h"
+#include "components/webdata/common/web_data_service_consumer.h"
+#include "google_apis/gaia/oauth2_token_service_delegate.h"
+#include "net/base/backoff_entry.h"
+#include "services/network/public/cpp/network_connection_tracker.h"
+
+class PrefRegistrySimple;
+class SigninClient;
+
+class MutableProfileOAuth2TokenServiceDelegate
+ : public OAuth2TokenServiceDelegate,
+ public WebDataServiceConsumer,
+ public network::NetworkConnectionTracker::NetworkConnectionObserver {
+ public:
+ using FixRequestErrorCallback = base::RepeatingCallback<bool()>;
+
+ MutableProfileOAuth2TokenServiceDelegate(
+ SigninClient* client,
+ AccountTrackerService* account_tracker_service,
+ network::NetworkConnectionTracker* network_connection_tracker,
+ scoped_refptr<TokenWebData> token_web_data,
+ signin::AccountConsistencyMethod account_consistency,
+ bool revoke_all_tokens_on_load,
+ bool can_revoke_credentials,
+ FixRequestErrorCallback fix_request_error_callback);
+ ~MutableProfileOAuth2TokenServiceDelegate() override;
+
+ static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+ // Overridden from OAuth2TokenServiceDelegate.
+ OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
+ const std::string& account_id,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ OAuth2AccessTokenConsumer* consumer) override;
+
+ // Updates the internal cache of the result from the most-recently-completed
+ // auth request (used for reporting errors to the user).
+ void UpdateAuthError(const std::string& account_id,
+ const GoogleServiceAuthError& error) override;
+
+ std::string GetTokenForMultilogin(
+ const std::string& account_id) const override;
+ bool RefreshTokenIsAvailable(const std::string& account_id) const override;
+ GoogleServiceAuthError GetAuthError(
+ const std::string& account_id) const override;
+ std::vector<std::string> GetAccounts() override;
+ scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory()
+ const override;
+ void LoadCredentials(const std::string& primary_account_id) override;
+ void UpdateCredentials(const std::string& account_id,
+ const std::string& refresh_token) override;
+ void RevokeAllCredentials() override;
+ void RevokeCredentials(const std::string& account_id) override;
+ void ExtractCredentials(OAuth2TokenService* to_service,
+ const std::string& account_id) override;
+ void Shutdown() override;
+
+ // Overridden from NetworkConnectionTracker::NetworkConnectionObserver.
+ void OnConnectionChanged(network::mojom::ConnectionType type) override;
+
+ // Overridden from OAuth2TokenServiceDelegate.
+ const net::BackoffEntry* BackoffEntry() const override;
+
+ bool FixRequestErrorIfPossible() override;
+
+ // Returns the account's refresh token used for testing purposes.
+ std::string GetRefreshTokenForTest(const std::string& account_id) const;
+
+ private:
+ friend class MutableProfileOAuth2TokenServiceDelegateTest;
+
+ class RevokeServerRefreshToken;
+
+ struct AccountStatus {
+ std::string refresh_token;
+ GoogleServiceAuthError last_auth_error;
+ };
+
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ PersistenceDBUpgrade);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ FetchPersistentError);
+ FRIEND_TEST_ALL_PREFIXES(
+ MutableProfileOAuth2TokenServiceDelegateTest,
+ PersistenceLoadCredentialsEmptyPrimaryAccountId_DiceEnabled);
+ FRIEND_TEST_ALL_PREFIXES(
+ MutableProfileOAuth2TokenServiceDelegateTest,
+ LoadCredentialsClearsTokenDBWhenNoPrimaryAccount_DiceDisabled);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ PersistenceLoadCredentials);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ RevokeOnUpdate);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ DelayedRevoke);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ DiceMigrationHostedDomainPrimaryAccount);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ ShutdownDuringRevoke);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ RevokeRetries);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ UpdateInvalidToken);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ LoadInvalidToken);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ GetAccounts);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ RetryBackoff);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ CanonicalizeAccountId);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ CanonAndNonCanonAccountId);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ ShutdownService);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ ClearTokensOnStartup);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ InvalidateTokensForMultilogin);
+ FRIEND_TEST_ALL_PREFIXES(MutableProfileOAuth2TokenServiceDelegateTest,
+ ExtractCredentials);
+
+ // WebDataServiceConsumer implementation:
+ void OnWebDataServiceRequestDone(
+ WebDataServiceBase::Handle handle,
+ std::unique_ptr<WDTypedResult> result) override;
+
+ // Loads credentials into in memory stucture.
+ void LoadAllCredentialsIntoMemory(
+ const std::map<std::string, std::string>& db_tokens);
+
+ // Updates the in-memory representation of the credentials.
+ void UpdateCredentialsInMemory(const std::string& account_id,
+ const std::string& refresh_token);
+
+ // Sets refresh token in error.
+ void InvalidateTokenForMultilogin(const std::string& failed_account) override;
+
+ // Persists credentials for |account_id|. Enables overriding for
+ // testing purposes, or other cases, when accessing the DB is not desired.
+ void PersistCredentials(const std::string& account_id,
+ const std::string& refresh_token);
+
+ // Clears credentials persisted for |account_id|. Enables overriding for
+ // testing purposes, or other cases, when accessing the DB is not desired.
+ void ClearPersistedCredentials(const std::string& account_id);
+
+ // Revokes the refresh token on the server.
+ void RevokeCredentialsOnServer(const std::string& refresh_token);
+
+ // Cancels any outstanding fetch for tokens from the web database.
+ void CancelWebTokenFetch();
+
+ std::string GetRefreshToken(const std::string& account_id) const;
+
+ // Creates a new AccountStatus and adds it to the AccountStatusMap.
+ // The account must not be already in the map.
+ void AddAccountStatus(const std::string& account_id,
+ const std::string& refresh_token,
+ const GoogleServiceAuthError& error);
+
+ // Called at when tokens are loaded. Performs housekeeping tasks and notifies
+ // the observers.
+ void FinishLoadingCredentials();
+
+ // Deletes the credential locally and notifies observers through
+ // OnRefreshTokenRevoked(). If |revoke_on_server| is true, the token is also
+ // revoked on the server.
+ void RevokeCredentialsImpl(const std::string& account_id,
+ bool revoke_on_server);
+
+ // Maps the |account_id| of accounts known to ProfileOAuth2TokenService
+ // to information about the account.
+ typedef std::map<std::string, AccountStatus> AccountStatusMap;
+ // In memory refresh token store mapping account_id to refresh_token.
+ AccountStatusMap refresh_tokens_;
+
+ // Handle to the request reading tokens from database.
+ WebDataServiceBase::Handle web_data_service_request_;
+
+ // The primary account id of this service's profile during the loading of
+ // credentials. This member is empty otherwise.
+ std::string loading_primary_account_id_;
+
+ std::vector<std::unique_ptr<RevokeServerRefreshToken>> server_revokes_;
+
+ // Used to verify that certain methods are called only on the thread on which
+ // this instance was created.
+ THREAD_CHECKER(thread_checker_);
+
+ // Used to rate-limit network token requests so as to not overload the server.
+ net::BackoffEntry::Policy backoff_policy_;
+ net::BackoffEntry backoff_entry_;
+ GoogleServiceAuthError backoff_error_;
+
+ SigninClient* client_;
+ AccountTrackerService* account_tracker_service_;
+ network::NetworkConnectionTracker* network_connection_tracker_;
+ scoped_refptr<TokenWebData> token_web_data_;
+ signin::AccountConsistencyMethod account_consistency_;
+
+ // Revokes all the tokens after loading them. Secondary accounts will be
+ // completely removed, and the primary account will be kept in authentication
+ // error state.
+ const bool revoke_all_tokens_on_load_;
+
+ // Supervised users cannot revoke credentials.
+ // TODO(droger): remove this when supervised users are no longer supported on
+ // any platform.
+ const bool can_revoke_credentials_;
+
+ // Callback function that attempts to correct request errors. Best effort
+ // only. Returns true if the error was fixed and retry should be reattempted.
+ FixRequestErrorCallback fix_request_error_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(MutableProfileOAuth2TokenServiceDelegate);
+};
+
+#endif // CHROME_BROWSER_SIGNIN_MUTABLE_PROFILE_OAUTH2_TOKEN_SERVICE_DELEGATE_H_
diff --git a/chromium/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate_unittest.cc b/chromium/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate_unittest.cc
new file mode 100644
index 00000000000..b9b8e588287
--- /dev/null
+++ b/chromium/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -0,0 +1,1615 @@
+// Copyright 2014 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 "components/signin/core/browser/mutable_profile_oauth2_token_service_delegate.h"
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "build/buildflag.h"
+#include "components/os_crypt/os_crypt_mocker.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/scoped_user_pref_update.h"
+#include "components/signin/core/browser/account_consistency_method.h"
+#include "components/signin/core/browser/account_info.h"
+#include "components/signin/core/browser/device_id_helper.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_buildflags.h"
+#include "components/signin/core/browser/signin_manager_base.h"
+#include "components/signin/core/browser/signin_pref_names.h"
+#include "components/signin/core/browser/test_signin_client.h"
+#include "components/signin/core/browser/webdata/token_web_data.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "components/webdata/common/web_data_service_base.h"
+#include "components/webdata/common/web_database_service.h"
+#include "google_apis/gaia/fake_oauth2_token_service_delegate.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_consumer.h"
+#include "google_apis/gaia/oauth2_token_service_test_util.h"
+#include "net/http/http_status_code.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/test/test_network_connection_tracker.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Defining constant here to handle backward compatiblity tests, but this
+// constant is no longer used in current versions of chrome.
+static const char kLSOService[] = "lso";
+static const char kEmail[] = "user@gmail.com";
+
+namespace {
+
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+// Create test account info.
+AccountInfo CreateTestAccountInfo(const std::string& name,
+ bool is_hosted_domain,
+ bool is_valid) {
+ AccountInfo account_info;
+ account_info.account_id = name;
+ account_info.gaia = name;
+ account_info.email = name + "@email.com";
+ account_info.full_name = "name";
+ account_info.given_name = "name";
+ if (is_valid) {
+ account_info.hosted_domain =
+ is_hosted_domain ? "example.com" : kNoHostedDomainFound;
+ }
+ account_info.locale = "en";
+ account_info.picture_url = "https://example.com";
+ account_info.is_child_account = false;
+ EXPECT_EQ(is_valid, account_info.IsValid());
+ return account_info;
+}
+#endif
+
+} // namespace
+
+class MutableProfileOAuth2TokenServiceDelegateTest
+ : public testing::Test,
+ public OAuth2AccessTokenConsumer,
+ public OAuth2TokenService::Observer,
+ public OAuth2TokenService::DiagnosticsObserver,
+ public WebDataServiceConsumer {
+ public:
+ MutableProfileOAuth2TokenServiceDelegateTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::UI,
+ base::test::ScopedTaskEnvironment::ExecutionMode::ASYNC),
+ access_token_success_count_(0),
+ access_token_failure_count_(0),
+ access_token_failure_(GoogleServiceAuthError::NONE),
+ token_available_count_(0),
+ token_revoked_count_(0),
+ tokens_loaded_count_(0),
+ start_batch_changes_(0),
+ end_batch_changes_(0),
+ auth_error_changed_count_(0),
+ revoke_all_tokens_on_load_(false) {}
+
+ void SetUp() override {
+ OSCryptMocker::SetUp();
+
+ MutableProfileOAuth2TokenServiceDelegate::RegisterProfilePrefs(
+ pref_service_.registry());
+ AccountTrackerService::RegisterPrefs(pref_service_.registry());
+ SigninManagerBase::RegisterProfilePrefs(pref_service_.registry());
+ client_.reset(new TestSigninClient(&pref_service_));
+ client_->test_url_loader_factory()->AddResponse(
+ GaiaUrls::GetInstance()->oauth2_revoke_url().spec(), "");
+ LoadTokenDatabase();
+ account_tracker_service_.Initialize(&pref_service_, base::FilePath());
+ }
+
+ void TearDown() override {
+ base::RunLoop().RunUntilIdle();
+ if (oauth2_service_delegate_) {
+ oauth2_service_delegate_->RemoveObserver(this);
+ oauth2_service_delegate_->Shutdown();
+ }
+ OSCryptMocker::TearDown();
+ }
+
+ void LoadTokenDatabase() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
+ scoped_refptr<WebDatabaseService> web_database =
+ new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get());
+ web_database->AddTable(std::make_unique<TokenServiceTable>());
+ web_database->LoadDatabase();
+ token_web_data_ =
+ new TokenWebData(web_database, base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get(),
+ WebDataServiceBase::ProfileErrorCallback());
+ token_web_data_->Init();
+ }
+
+ void AddSuccessfulOAuhTokenResponse() {
+ client_->test_url_loader_factory()->AddResponse(
+ GaiaUrls::GetInstance()->oauth2_token_url().spec(),
+ GetValidTokenResponse("token", 3600));
+ }
+
+ std::unique_ptr<MutableProfileOAuth2TokenServiceDelegate>
+ CreateOAuth2ServiceDelegate(
+ signin::AccountConsistencyMethod account_consistency) {
+ return std::make_unique<MutableProfileOAuth2TokenServiceDelegate>(
+ client_.get(), &account_tracker_service_,
+ network::TestNetworkConnectionTracker::GetInstance(), token_web_data_,
+ account_consistency, revoke_all_tokens_on_load_,
+ true /* can_revoke_credantials */,
+ MutableProfileOAuth2TokenServiceDelegate::FixRequestErrorCallback());
+ }
+
+ void InitializeOAuth2ServiceDelegate(
+ signin::AccountConsistencyMethod account_consistency) {
+ oauth2_service_delegate_ = CreateOAuth2ServiceDelegate(account_consistency);
+ oauth2_service_delegate_->AddObserver(this);
+ }
+
+ void AddAuthTokenManually(const std::string& service,
+ const std::string& value) {
+ if (token_web_data_)
+ token_web_data_->SetTokenForService(service, value);
+ }
+
+ // WebDataServiceConsumer implementation
+ void OnWebDataServiceRequestDone(
+ WebDataServiceBase::Handle h,
+ std::unique_ptr<WDTypedResult> result) override {
+ DCHECK(!token_web_data_result_);
+ DCHECK_EQ(TOKEN_RESULT, result->GetType());
+ token_web_data_result_.reset(
+ static_cast<WDResult<TokenResult>*>(result.release()));
+ }
+
+ // OAuth2AccessTokenConusmer implementation
+ void OnGetTokenSuccess(
+ const OAuth2AccessTokenConsumer::TokenResponse& token_response) override {
+ ++access_token_success_count_;
+ }
+
+ void OnGetTokenFailure(const GoogleServiceAuthError& error) override {
+ ++access_token_failure_count_;
+ access_token_failure_ = error;
+ }
+
+ // OAuth2TokenService::Observer implementation.
+ void OnRefreshTokenAvailable(const std::string& account_id) override {
+ ++token_available_count_;
+ }
+ void OnRefreshTokenRevoked(const std::string& account_id) override {
+ ++token_revoked_count_;
+ }
+ void OnRefreshTokensLoaded() override { ++tokens_loaded_count_; }
+
+ void OnStartBatchChanges() override { ++start_batch_changes_; }
+
+ void OnEndBatchChanges() override { ++end_batch_changes_; }
+
+ void OnAuthErrorChanged(const std::string& account_id,
+ const GoogleServiceAuthError& auth_error) override {
+ ++auth_error_changed_count_;
+ }
+
+ // OAuth2TokenService::DiagnosticsObserver implementation
+ void OnRefreshTokenAvailableFromSource(const std::string& account_id,
+ bool is_refresh_token_valid,
+ const std::string& source) override {
+ source_for_refresh_token_available_ = source;
+ }
+ void OnRefreshTokenRevokedFromSource(const std::string& account_id,
+ const std::string& source) override {
+ source_for_refresh_token_revoked_ = source;
+ }
+
+ void ResetObserverCounts() {
+ token_available_count_ = 0;
+ token_revoked_count_ = 0;
+ tokens_loaded_count_ = 0;
+ start_batch_changes_ = 0;
+ end_batch_changes_ = 0;
+ auth_error_changed_count_ = 0;
+ }
+
+ void ExpectNoNotifications() {
+ EXPECT_EQ(0, token_available_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ ResetObserverCounts();
+ }
+
+ void ExpectOneTokenAvailableNotification() {
+ EXPECT_EQ(1, token_available_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ ResetObserverCounts();
+ }
+
+ void ExpectOneTokenRevokedNotification() {
+ EXPECT_EQ(0, token_available_count_);
+ EXPECT_EQ(1, token_revoked_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ ResetObserverCounts();
+ }
+
+ void ExpectOneTokensLoadedNotification() {
+ EXPECT_EQ(0, token_available_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_EQ(1, tokens_loaded_count_);
+ ResetObserverCounts();
+ }
+
+ protected:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ base::ScopedTempDir temp_dir_;
+ std::unique_ptr<TestSigninClient> client_;
+ std::unique_ptr<MutableProfileOAuth2TokenServiceDelegate>
+ oauth2_service_delegate_;
+ TestingOAuth2TokenServiceConsumer consumer_;
+ sync_preferences::TestingPrefServiceSyncable pref_service_;
+ AccountTrackerService account_tracker_service_;
+ scoped_refptr<TokenWebData> token_web_data_;
+ std::unique_ptr<WDResult<TokenResult>> token_web_data_result_;
+ int access_token_success_count_;
+ int access_token_failure_count_;
+ GoogleServiceAuthError access_token_failure_;
+ int token_available_count_;
+ int token_revoked_count_;
+ int tokens_loaded_count_;
+ int start_batch_changes_;
+ int end_batch_changes_;
+ int auth_error_changed_count_;
+ bool revoke_all_tokens_on_load_;
+ std::string source_for_refresh_token_available_;
+ std::string source_for_refresh_token_revoked_;
+};
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, PersistenceDBUpgrade) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kMirror);
+ std::string main_account_id("account_id");
+ std::string main_refresh_token("old_refresh_token");
+
+ // Populate DB with legacy tokens.
+ AddAuthTokenManually(GaiaConstants::kSyncService, "syncServiceToken");
+ AddAuthTokenManually(kLSOService, "lsoToken");
+ AddAuthTokenManually(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
+ main_refresh_token);
+
+ // Force LoadCredentials.
+ oauth2_service_delegate_->LoadCredentials(main_account_id);
+ base::RunLoop().RunUntilIdle();
+
+ // Legacy tokens get discarded, but the old refresh token is kept.
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(1, token_available_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_TRUE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable(main_account_id));
+ EXPECT_EQ(1U, oauth2_service_delegate_->refresh_tokens_.size());
+ EXPECT_EQ(
+ main_refresh_token,
+ oauth2_service_delegate_->refresh_tokens_[main_account_id].refresh_token);
+
+ // Add an old legacy token to the DB, to ensure it will not overwrite existing
+ // credentials for main account.
+ AddAuthTokenManually(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
+ "secondOldRefreshToken");
+ // Add some other legacy token. (Expected to get discarded).
+ AddAuthTokenManually(kLSOService, "lsoToken");
+ // Also add a token using PO2TS.UpdateCredentials and make sure upgrade does
+ // not wipe it.
+ std::string other_account_id("other_account_id");
+ std::string other_refresh_token("other_refresh_token");
+ oauth2_service_delegate_->UpdateCredentials(other_account_id,
+ other_refresh_token);
+ ResetObserverCounts();
+
+ // Force LoadCredentials.
+ oauth2_service_delegate_->LoadCredentials(main_account_id);
+ base::RunLoop().RunUntilIdle();
+
+ // Again legacy tokens get discarded, but since the main porfile account
+ // token is present it is not overwritten.
+ EXPECT_EQ(2, token_available_count_);
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_EQ(main_refresh_token,
+ oauth2_service_delegate_->GetRefreshToken(main_account_id));
+ EXPECT_TRUE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable(main_account_id));
+ // TODO(fgorski): cover both using RefreshTokenIsAvailable() and then get the
+ // tokens using GetRefreshToken()
+ EXPECT_EQ(2U, oauth2_service_delegate_->refresh_tokens_.size());
+ EXPECT_EQ(
+ main_refresh_token,
+ oauth2_service_delegate_->refresh_tokens_[main_account_id].refresh_token);
+ EXPECT_EQ(other_refresh_token,
+ oauth2_service_delegate_->refresh_tokens_[other_account_id]
+ .refresh_token);
+
+ oauth2_service_delegate_->RevokeAllCredentials();
+ EXPECT_EQ(2, start_batch_changes_);
+ EXPECT_EQ(2, end_batch_changes_);
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ PersistenceRevokeCredentials) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ std::string account_id_1 = "account_id_1";
+ std::string refresh_token_1 = "refresh_token_1";
+ std::string account_id_2 = "account_id_2";
+ std::string refresh_token_2 = "refresh_token_2";
+
+ EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(account_id_1));
+ EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(account_id_2));
+ oauth2_service_delegate_->UpdateCredentials(account_id_1, refresh_token_1);
+ oauth2_service_delegate_->UpdateCredentials(account_id_2, refresh_token_2);
+ EXPECT_EQ(2, start_batch_changes_);
+ EXPECT_EQ(2, end_batch_changes_);
+
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(account_id_1));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(account_id_2));
+
+ ResetObserverCounts();
+ oauth2_service_delegate_->RevokeCredentials(account_id_1);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ ExpectOneTokenRevokedNotification();
+
+ EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(account_id_1));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(account_id_2));
+
+ oauth2_service_delegate_->RevokeAllCredentials();
+ EXPECT_EQ(0, token_available_count_);
+ EXPECT_EQ(1, token_revoked_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ ResetObserverCounts();
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ LoadCredentialsStateEmptyPrimaryAccountId) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ // Ensure DB is clean.
+ oauth2_service_delegate_->RevokeAllCredentials();
+
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_NOT_STARTED,
+ oauth2_service_delegate_->load_credentials_state());
+ oauth2_service_delegate_->LoadCredentials("");
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS,
+ oauth2_service_delegate_->load_credentials_state());
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ PersistenceLoadCredentials) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kMirror);
+
+ // Ensure DB is clean.
+ oauth2_service_delegate_->RevokeAllCredentials();
+ ResetObserverCounts();
+
+ // Perform a load from an empty DB.
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_NOT_STARTED,
+ oauth2_service_delegate_->load_credentials_state());
+ oauth2_service_delegate_->LoadCredentials("account_id");
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_IN_PROGRESS,
+ oauth2_service_delegate_->load_credentials_state());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(OAuth2TokenServiceDelegate::
+ LOAD_CREDENTIALS_FINISHED_WITH_NO_TOKEN_FOR_PRIMARY_ACCOUNT,
+ oauth2_service_delegate_->load_credentials_state());
+ EXPECT_EQ(GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_MISSING),
+ oauth2_service_delegate_->GetAuthError("account_id"));
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_EQ(1, auth_error_changed_count_);
+
+ // A"tokens loaded" notification should have been fired.
+ EXPECT_EQ(1, tokens_loaded_count_);
+
+ // As the delegate puts the primary account into the token map with an invalid
+ // token in the case of loading from an empty TB, a "token available"
+ // notification should have been fired as well.
+ EXPECT_EQ(1, token_available_count_);
+
+ ResetObserverCounts();
+
+ // LoadCredentials() guarantees that the account given to it as argument
+ // is in the refresh_token map.
+ EXPECT_EQ(1U, oauth2_service_delegate_->refresh_tokens_.size());
+ EXPECT_EQ(
+ MutableProfileOAuth2TokenServiceDelegate::kInvalidRefreshToken,
+ oauth2_service_delegate_->refresh_tokens_["account_id"].refresh_token);
+ // Setup a DB with tokens that don't require upgrade and clear memory.
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
+ oauth2_service_delegate_->UpdateCredentials("account_id2", "refresh_token2");
+ oauth2_service_delegate_->refresh_tokens_.clear();
+ EXPECT_EQ(2, start_batch_changes_);
+ EXPECT_EQ(2, end_batch_changes_);
+ EXPECT_EQ(2, auth_error_changed_count_);
+ ResetObserverCounts();
+
+ oauth2_service_delegate_->LoadCredentials("account_id");
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_IN_PROGRESS,
+ oauth2_service_delegate_->load_credentials_state());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS,
+ oauth2_service_delegate_->load_credentials_state());
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ oauth2_service_delegate_->GetAuthError("account_id"));
+ EXPECT_EQ(2, token_available_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_EQ(2, auth_error_changed_count_);
+ ResetObserverCounts();
+
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable("account_id"));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable("account_id2"));
+
+ oauth2_service_delegate_->RevokeAllCredentials();
+ EXPECT_EQ(0, token_available_count_);
+ EXPECT_EQ(2, token_revoked_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_EQ(0, auth_error_changed_count_);
+ ResetObserverCounts();
+}
+
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ PersistenceLoadCredentialsEmptyPrimaryAccountId_DiceEnabled) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDice);
+
+ // Ensure DB is clean.
+ oauth2_service_delegate_->RevokeAllCredentials();
+ ResetObserverCounts();
+ // Perform a load from an empty DB.
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_NOT_STARTED,
+ oauth2_service_delegate_->load_credentials_state());
+ oauth2_service_delegate_->LoadCredentials("");
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_IN_PROGRESS,
+ oauth2_service_delegate_->load_credentials_state());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS,
+ oauth2_service_delegate_->load_credentials_state());
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_EQ(0, auth_error_changed_count_);
+ ExpectOneTokensLoadedNotification();
+
+ // No account should be present in the refresh token as no primary account
+ // was passed to the token service.
+ EXPECT_TRUE(oauth2_service_delegate_->refresh_tokens_.empty());
+
+ // Setup a DB with tokens that don't require upgrade and clear memory.
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
+ oauth2_service_delegate_->UpdateCredentials("account_id2", "refresh_token2");
+ oauth2_service_delegate_->refresh_tokens_.clear();
+ EXPECT_EQ(2, start_batch_changes_);
+ EXPECT_EQ(2, end_batch_changes_);
+ EXPECT_EQ(2, auth_error_changed_count_);
+ ResetObserverCounts();
+
+ oauth2_service_delegate_->LoadCredentials("");
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_IN_PROGRESS,
+ oauth2_service_delegate_->load_credentials_state());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS,
+ oauth2_service_delegate_->load_credentials_state());
+ EXPECT_EQ(2, token_available_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_EQ(2, auth_error_changed_count_);
+ ResetObserverCounts();
+
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable("account_id"));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable("account_id2"));
+
+ oauth2_service_delegate_->RevokeAllCredentials();
+ EXPECT_EQ(0, token_available_count_);
+ EXPECT_EQ(2, token_revoked_count_);
+ EXPECT_EQ(0, tokens_loaded_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_EQ(0, auth_error_changed_count_);
+ ResetObserverCounts();
+}
+
+// Tests that Dice migration does not happen if an account is invalid. In
+// particular, no hosted domain tokens are revoked.
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ DiceNoMigrationOnInvalidAccount) {
+ ASSERT_FALSE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+ InitializeOAuth2ServiceDelegate(
+ signin::AccountConsistencyMethod::kDiceMigration);
+ oauth2_service_delegate_->RevokeAllCredentials();
+
+ // Add account info to the account tracker.
+ AccountInfo primary_account = CreateTestAccountInfo(
+ "primary_account", true /* is_hosted_domain*/, true /* is_valid*/);
+ AccountInfo secondary_account = CreateTestAccountInfo(
+ "secondary_account", false /* is_hosted_domain*/, false /* is_valid*/);
+ account_tracker_service_.SeedAccountInfo(primary_account);
+ account_tracker_service_.SeedAccountInfo(secondary_account);
+
+ ResetObserverCounts();
+ AddAuthTokenManually("AccountId-" + primary_account.account_id,
+ "refresh_token");
+ AddAuthTokenManually("AccountId-" + secondary_account.account_id,
+ "refresh_token");
+ oauth2_service_delegate_->LoadCredentials(primary_account.account_id);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(2, token_available_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_EQ(2, auth_error_changed_count_);
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(
+ primary_account.account_id));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(
+ secondary_account.account_id));
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS,
+ oauth2_service_delegate_->load_credentials_state());
+
+ EXPECT_FALSE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+}
+
+// Tests that the migration happened after loading consummer accounts.
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ DiceMigrationConsummerAccounts) {
+ ASSERT_EQ(AccountTrackerService::MIGRATION_DONE,
+ account_tracker_service_.GetMigrationState());
+ ASSERT_FALSE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+ InitializeOAuth2ServiceDelegate(
+ signin::AccountConsistencyMethod::kDiceMigration);
+ oauth2_service_delegate_->RevokeAllCredentials();
+
+ // Add account info to the account tracker.
+ AccountInfo primary_account = CreateTestAccountInfo(
+ "primary_account", false /* is_hosted_domain*/, true /* is_valid*/);
+ AccountInfo secondary_account = CreateTestAccountInfo(
+ "secondary_account", false /* is_hosted_domain*/, true /* is_valid*/);
+ account_tracker_service_.SeedAccountInfo(primary_account);
+ account_tracker_service_.SeedAccountInfo(secondary_account);
+
+ ResetObserverCounts();
+ AddAuthTokenManually("AccountId-" + primary_account.account_id,
+ "refresh_token");
+ AddAuthTokenManually("AccountId-" + secondary_account.account_id,
+ "refresh_token");
+ oauth2_service_delegate_->LoadCredentials(primary_account.account_id);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(2, token_available_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_EQ(2, auth_error_changed_count_);
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(
+ primary_account.account_id));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(
+ secondary_account.account_id));
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS,
+ oauth2_service_delegate_->load_credentials_state());
+
+ EXPECT_TRUE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+}
+
+// Tests that the migration revokes the hosted domain tokens.
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ DiceMigrationHostedDomainAccounts) {
+ ASSERT_EQ(AccountTrackerService::MIGRATION_DONE,
+ account_tracker_service_.GetMigrationState());
+ ASSERT_FALSE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+ InitializeOAuth2ServiceDelegate(
+ signin::AccountConsistencyMethod::kDiceMigration);
+ oauth2_service_delegate_->RevokeAllCredentials();
+
+ // Add account info to the account tracker.
+ AccountInfo primary_account = CreateTestAccountInfo(
+ "primary_account", false /* is_hosted_domain*/, true /* is_valid*/);
+ AccountInfo secondary_account = CreateTestAccountInfo(
+ "secondary_account", true /* is_hosted_domain*/, true /* is_valid*/);
+ account_tracker_service_.SeedAccountInfo(primary_account);
+ account_tracker_service_.SeedAccountInfo(secondary_account);
+
+ ResetObserverCounts();
+ AddAuthTokenManually("AccountId-" + primary_account.account_id,
+ "refresh_token");
+ AddAuthTokenManually("AccountId-" + secondary_account.account_id,
+ "refresh_token");
+ oauth2_service_delegate_->LoadCredentials(primary_account.account_id);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(1, token_available_count_);
+ EXPECT_EQ(1, token_revoked_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_EQ(1, auth_error_changed_count_);
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(
+ primary_account.account_id));
+ EXPECT_EQ(OAuth2TokenServiceDelegate::LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS,
+ oauth2_service_delegate_->load_credentials_state());
+
+ EXPECT_TRUE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+}
+
+// Tests that the migration can revoke the primary token too.
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ DiceMigrationHostedDomainPrimaryAccount) {
+ ASSERT_EQ(AccountTrackerService::MIGRATION_DONE,
+ account_tracker_service_.GetMigrationState());
+ ASSERT_FALSE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+ InitializeOAuth2ServiceDelegate(
+ signin::AccountConsistencyMethod::kDiceMigration);
+ oauth2_service_delegate_->RevokeAllCredentials();
+
+ // Add account info to the account tracker.
+ AccountInfo primary_account = CreateTestAccountInfo(
+ "primary_account", true /* is_hosted_domain*/, true /* is_valid*/);
+ account_tracker_service_.SeedAccountInfo(primary_account);
+
+ ResetObserverCounts();
+ AddAuthTokenManually("AccountId-" + primary_account.account_id,
+ "refresh_token");
+ oauth2_service_delegate_->LoadCredentials(primary_account.account_id);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(1, token_revoked_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_EQ(1, auth_error_changed_count_);
+
+ // After having revoked the primary account's token during loading, the
+ // delegate should have noticed that it had no token for the primary account
+ // when the load was complete and inserted an invalid token for that account.
+ EXPECT_EQ(1, token_available_count_);
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(
+ primary_account.account_id));
+ EXPECT_EQ(
+ MutableProfileOAuth2TokenServiceDelegate::kInvalidRefreshToken,
+ oauth2_service_delegate_->refresh_tokens_[primary_account.account_id]
+ .refresh_token);
+ EXPECT_EQ(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::CREDENTIALS_MISSING,
+ oauth2_service_delegate_->GetAuthError(primary_account.account_id)
+ .GetInvalidGaiaCredentialsReason());
+ EXPECT_EQ(OAuth2TokenServiceDelegate::
+ LOAD_CREDENTIALS_FINISHED_WITH_NO_TOKEN_FOR_PRIMARY_ACCOUNT,
+ oauth2_service_delegate_->load_credentials_state());
+
+ EXPECT_TRUE(pref_service_.GetBoolean(prefs::kTokenServiceDiceCompatible));
+}
+
+#endif // BUILDFLAG(ENABLE_DICE_SUPPORT)
+
+#if !defined(OS_CHROMEOS)
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ LoadCredentialsClearsTokenDBWhenNoPrimaryAccount_DiceDisabled) {
+ // Populate DB with 2 valid tokens.
+ AddAuthTokenManually("AccountId-12345", "refresh_token");
+ AddAuthTokenManually("AccountId-67890", "refresh_token");
+
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ oauth2_service_delegate_->LoadCredentials(/*primary_account_id=*/"");
+ base::RunLoop().RunUntilIdle();
+
+ // No tokens were loaded.
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(0, token_available_count_);
+ EXPECT_EQ(2, token_revoked_count_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_EQ(0U, oauth2_service_delegate_->refresh_tokens_.size());
+
+ // Handle to the request reading tokens from database.
+ token_web_data_->GetAllTokens(this);
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(token_web_data_result_.get());
+ ASSERT_EQ(0u, token_web_data_result_->GetValue().tokens.size());
+}
+#endif // !defined(OS_CHROMEOS)
+
+// Tests that calling UpdateCredentials revokes the old token, without sending
+// the notification.
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, RevokeOnUpdate) {
+ // Add a token.
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ ASSERT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+ ExpectOneTokenAvailableNotification();
+
+ // Updating the token does not revoke the old one.
+ // Regression test for http://crbug.com/865189
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token2");
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+ ExpectOneTokenAvailableNotification();
+
+ // Flush the server revokes.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+
+ // Set the same token again.
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token2");
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+ ExpectNoNotifications();
+
+ // Clear the token.
+ oauth2_service_delegate_->RevokeAllCredentials();
+ EXPECT_EQ(1u, oauth2_service_delegate_->server_revokes_.size());
+ ExpectOneTokenRevokedNotification();
+
+ // Flush the server revokes.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, DelayedRevoke) {
+ client_->SetNetworkCallsDelayed(true);
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+ oauth2_service_delegate_->RevokeCredentials("account_id");
+
+ // The revoke does not start until network calls are unblocked.
+ EXPECT_EQ(1u, oauth2_service_delegate_->server_revokes_.size());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1u, oauth2_service_delegate_->server_revokes_.size());
+
+ // Unblock network calls, and check that the revocation goes through.
+ client_->SetNetworkCallsDelayed(false);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, ShutdownDuringRevoke) {
+ // Shutdown cancels the revocation.
+ client_->SetNetworkCallsDelayed(true);
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
+ oauth2_service_delegate_->RevokeCredentials("account_id");
+ EXPECT_EQ(1u, oauth2_service_delegate_->server_revokes_.size());
+
+ // Shutdown.
+ oauth2_service_delegate_->Shutdown();
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+
+ // Unblocking network calls after shutdown does not crash.
+ client_->SetNetworkCallsDelayed(false);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, RevokeRetries) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ const std::string url = GaiaUrls::GetInstance()->oauth2_revoke_url().spec();
+ // Revokes will remain in "pending" state.
+ client_->test_url_loader_factory()->ClearResponses();
+
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+ EXPECT_FALSE(client_->test_url_loader_factory()->IsPending(url));
+
+ oauth2_service_delegate_->RevokeCredentials("account_id");
+ EXPECT_EQ(1u, oauth2_service_delegate_->server_revokes_.size());
+ EXPECT_TRUE(client_->test_url_loader_factory()->IsPending(url));
+ // Fail and retry.
+ client_->test_url_loader_factory()->SimulateResponseForPendingRequest(
+ url, std::string(), net::HTTP_INTERNAL_SERVER_ERROR);
+ EXPECT_TRUE(client_->test_url_loader_factory()->IsPending(url));
+ EXPECT_EQ(1u, oauth2_service_delegate_->server_revokes_.size());
+ // Fail and retry.
+ client_->test_url_loader_factory()->SimulateResponseForPendingRequest(
+ url, std::string(), net::HTTP_INTERNAL_SERVER_ERROR);
+ EXPECT_TRUE(client_->test_url_loader_factory()->IsPending(url));
+ EXPECT_EQ(1u, oauth2_service_delegate_->server_revokes_.size());
+ // Do not retry after third attempt.
+ client_->test_url_loader_factory()->SimulateResponseForPendingRequest(
+ url, std::string(), net::HTTP_INTERNAL_SERVER_ERROR);
+ EXPECT_FALSE(client_->test_url_loader_factory()->IsPending(url));
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+
+ // No retry after success.
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
+ oauth2_service_delegate_->RevokeCredentials("account_id");
+ EXPECT_EQ(1u, oauth2_service_delegate_->server_revokes_.size());
+ EXPECT_TRUE(client_->test_url_loader_factory()->IsPending(url));
+ client_->test_url_loader_factory()->SimulateResponseForPendingRequest(
+ url, std::string(), net::HTTP_OK);
+ EXPECT_FALSE(client_->test_url_loader_factory()->IsPending(url));
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, UpdateInvalidToken) {
+ // Add the invalid token.
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ ASSERT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+ oauth2_service_delegate_->UpdateCredentials(
+ "account_id",
+ MutableProfileOAuth2TokenServiceDelegate::kInvalidRefreshToken);
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+ EXPECT_EQ(1, auth_error_changed_count_);
+ ExpectOneTokenAvailableNotification();
+
+ // The account is in authentication error.
+ EXPECT_EQ(GoogleServiceAuthError(
+ GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_CLIENT)),
+ oauth2_service_delegate_->GetAuthError("account_id"));
+
+ // Update the token: authentication error is fixed, no actual server
+ // revocation.
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+ EXPECT_EQ(1, auth_error_changed_count_);
+ ExpectOneTokenAvailableNotification();
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ oauth2_service_delegate_->GetAuthError("account_id"));
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ InvalidateTokensForMultilogin) {
+ class TokenServiceErrorObserver : public OAuth2TokenService::Observer {
+ public:
+ MOCK_METHOD2(OnAuthErrorChanged,
+ void(const std::string&, const GoogleServiceAuthError&));
+ };
+
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDice);
+ TokenServiceErrorObserver observer;
+ oauth2_service_delegate_->AddObserver(&observer);
+
+ const std::string account_id1 = "account_id1";
+ const std::string account_id2 = "account_id2";
+
+ // This will be fired from UpdateCredentials.
+ EXPECT_CALL(
+ observer,
+ OnAuthErrorChanged(::testing::_, GoogleServiceAuthError::AuthErrorNone()))
+ .Times(2);
+ oauth2_service_delegate_->UpdateCredentials(account_id1, "refresh_token1");
+ oauth2_service_delegate_->UpdateCredentials(account_id2, "refresh_token2");
+
+ testing::Mock::VerifyAndClearExpectations(&observer);
+
+ // This should be fired after error is set.
+ EXPECT_CALL(
+ observer,
+ OnAuthErrorChanged(account_id1,
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)))
+ .Times(1);
+
+ oauth2_service_delegate_->InvalidateTokenForMultilogin(account_id1);
+ EXPECT_EQ(oauth2_service_delegate_->GetAuthError(account_id1).state(),
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
+ EXPECT_EQ(oauth2_service_delegate_->GetAuthError(account_id2).state(),
+ GoogleServiceAuthError::NONE);
+
+ oauth2_service_delegate_->RemoveObserver(&observer);
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, LoadInvalidToken) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDice);
+ std::map<std::string, std::string> tokens;
+ tokens["AccountId-account_id"] =
+ MutableProfileOAuth2TokenServiceDelegate::kInvalidRefreshToken;
+
+ oauth2_service_delegate_->LoadAllCredentialsIntoMemory(tokens);
+
+ EXPECT_EQ(1u, oauth2_service_delegate_->GetAccounts().size());
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable("account_id"));
+ EXPECT_STREQ(MutableProfileOAuth2TokenServiceDelegate::kInvalidRefreshToken,
+ oauth2_service_delegate_->GetRefreshToken("account_id").c_str());
+
+ // The account is in authentication error.
+ EXPECT_EQ(GoogleServiceAuthError(
+ GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_CLIENT)),
+ oauth2_service_delegate_->GetAuthError("account_id"));
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, GetTokenForMultilogin) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDice);
+ const std::string account_id1 = "account_id1";
+ const std::string account_id2 = "account_id2";
+
+ oauth2_service_delegate_->UpdateCredentials(account_id1, "refresh_token1");
+ oauth2_service_delegate_->UpdateCredentials(account_id2, "refresh_token2");
+ oauth2_service_delegate_->UpdateAuthError(
+ account_id2,
+ GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+
+ EXPECT_EQ(oauth2_service_delegate_->GetTokenForMultilogin(account_id1),
+ "refresh_token1");
+ EXPECT_EQ(oauth2_service_delegate_->GetTokenForMultilogin(account_id2),
+ std::string());
+ EXPECT_EQ(oauth2_service_delegate_->GetTokenForMultilogin("unknown account"),
+ std::string());
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, PersistenceNotifications) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
+ ExpectOneTokenAvailableNotification();
+
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
+ ExpectNoNotifications();
+
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token2");
+ ExpectOneTokenAvailableNotification();
+
+ oauth2_service_delegate_->RevokeCredentials("account_id");
+ ExpectOneTokenRevokedNotification();
+
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token2");
+ ExpectOneTokenAvailableNotification();
+
+ oauth2_service_delegate_->RevokeAllCredentials();
+ ResetObserverCounts();
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, GetAccounts) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ EXPECT_TRUE(oauth2_service_delegate_->GetAccounts().empty());
+ oauth2_service_delegate_->UpdateCredentials("account_id1", "refresh_token1");
+ oauth2_service_delegate_->UpdateCredentials("account_id2", "refresh_token2");
+ std::vector<std::string> accounts = oauth2_service_delegate_->GetAccounts();
+ EXPECT_EQ(2u, accounts.size());
+ EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id1"));
+ EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id2"));
+ oauth2_service_delegate_->RevokeCredentials("account_id2");
+ accounts = oauth2_service_delegate_->GetAccounts();
+ EXPECT_EQ(1u, oauth2_service_delegate_->GetAccounts().size());
+ EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id1"));
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, FetchPersistentError) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ oauth2_service_delegate_->UpdateCredentials(kEmail, "refreshToken");
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ oauth2_service_delegate_->GetAuthError(kEmail));
+
+ GoogleServiceAuthError authfail(GoogleServiceAuthError::ACCOUNT_DELETED);
+ oauth2_service_delegate_->UpdateAuthError(kEmail, authfail);
+ EXPECT_NE(GoogleServiceAuthError::AuthErrorNone(),
+ oauth2_service_delegate_->GetAuthError(kEmail));
+
+ // Create a "success" fetch we don't expect to get called.
+ AddSuccessfulOAuhTokenResponse();
+
+ EXPECT_EQ(0, access_token_success_count_);
+ EXPECT_EQ(0, access_token_failure_count_);
+ std::vector<std::string> scope_list;
+ scope_list.push_back("scope");
+ std::unique_ptr<OAuth2AccessTokenFetcher> fetcher(
+ oauth2_service_delegate_->CreateAccessTokenFetcher(
+ kEmail, oauth2_service_delegate_->GetURLLoaderFactory(), this));
+ fetcher->Start("foo", "bar", scope_list);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, access_token_success_count_);
+ EXPECT_EQ(1, access_token_failure_count_);
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, RetryBackoff) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ oauth2_service_delegate_->UpdateCredentials(kEmail, "refreshToken");
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ oauth2_service_delegate_->GetAuthError(kEmail));
+
+ GoogleServiceAuthError authfail(GoogleServiceAuthError::SERVICE_UNAVAILABLE);
+ oauth2_service_delegate_->UpdateAuthError(kEmail, authfail);
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ oauth2_service_delegate_->GetAuthError(kEmail));
+
+ // Create a "success" fetch we don't expect to get called just yet.
+ AddSuccessfulOAuhTokenResponse();
+
+ // Transient error will repeat until backoff period expires.
+ EXPECT_EQ(0, access_token_success_count_);
+ EXPECT_EQ(0, access_token_failure_count_);
+ std::vector<std::string> scope_list;
+ scope_list.push_back("scope");
+ std::unique_ptr<OAuth2AccessTokenFetcher> fetcher1(
+ oauth2_service_delegate_->CreateAccessTokenFetcher(
+ kEmail, oauth2_service_delegate_->GetURLLoaderFactory(), this));
+ fetcher1->Start("foo", "bar", scope_list);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, access_token_success_count_);
+ EXPECT_EQ(1, access_token_failure_count_);
+ // Expect a positive backoff time.
+ EXPECT_GT(oauth2_service_delegate_->backoff_entry_.GetTimeUntilRelease(),
+ base::TimeDelta());
+
+ // Pretend that backoff has expired and try again.
+ oauth2_service_delegate_->backoff_entry_.SetCustomReleaseTime(
+ base::TimeTicks());
+ std::unique_ptr<OAuth2AccessTokenFetcher> fetcher2(
+ oauth2_service_delegate_->CreateAccessTokenFetcher(
+ kEmail, oauth2_service_delegate_->GetURLLoaderFactory(), this));
+ fetcher2->Start("foo", "bar", scope_list);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, access_token_success_count_);
+ EXPECT_EQ(1, access_token_failure_count_);
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, ResetBackoff) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ oauth2_service_delegate_->UpdateCredentials(kEmail, "refreshToken");
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ oauth2_service_delegate_->GetAuthError(kEmail));
+
+ GoogleServiceAuthError authfail(GoogleServiceAuthError::SERVICE_UNAVAILABLE);
+ oauth2_service_delegate_->UpdateAuthError(kEmail, authfail);
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ oauth2_service_delegate_->GetAuthError(kEmail));
+
+ // Create a "success" fetch we don't expect to get called just yet.
+ AddSuccessfulOAuhTokenResponse();
+
+ // Transient error will repeat until backoff period expires.
+ EXPECT_EQ(0, access_token_success_count_);
+ EXPECT_EQ(0, access_token_failure_count_);
+ std::vector<std::string> scope_list;
+ scope_list.push_back("scope");
+ std::unique_ptr<OAuth2AccessTokenFetcher> fetcher1(
+ oauth2_service_delegate_->CreateAccessTokenFetcher(
+ kEmail, oauth2_service_delegate_->GetURLLoaderFactory(), this));
+ fetcher1->Start("foo", "bar", scope_list);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0, access_token_success_count_);
+ EXPECT_EQ(1, access_token_failure_count_);
+
+ // Notify of network change and ensure that request now runs.
+ oauth2_service_delegate_->OnConnectionChanged(
+ network::mojom::ConnectionType::CONNECTION_WIFI);
+ std::unique_ptr<OAuth2AccessTokenFetcher> fetcher2(
+ oauth2_service_delegate_->CreateAccessTokenFetcher(
+ kEmail, oauth2_service_delegate_->GetURLLoaderFactory(), this));
+ fetcher2->Start("foo", "bar", scope_list);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, access_token_success_count_);
+ EXPECT_EQ(1, access_token_failure_count_);
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, CanonicalizeAccountId) {
+ pref_service_.SetInteger(prefs::kAccountIdMigrationState,
+ AccountTrackerService::MIGRATION_NOT_STARTED);
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kMirror);
+ std::map<std::string, std::string> tokens;
+ tokens["AccountId-user@gmail.com"] = "refresh_token";
+ tokens["AccountId-Foo.Bar@gmail.com"] = "refresh_token";
+ tokens["AccountId-12345"] = "refresh_token";
+
+ oauth2_service_delegate_->LoadAllCredentialsIntoMemory(tokens);
+
+ EXPECT_TRUE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable("user@gmail.com"));
+ EXPECT_TRUE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable("foobar@gmail.com"));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable("12345"));
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ CanonAndNonCanonAccountId) {
+ pref_service_.SetInteger(prefs::kAccountIdMigrationState,
+ AccountTrackerService::MIGRATION_NOT_STARTED);
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kMirror);
+ std::map<std::string, std::string> tokens;
+ tokens["AccountId-Foo.Bar@gmail.com"] = "bad_token";
+ tokens["AccountId-foobar@gmail.com"] = "good_token";
+
+ oauth2_service_delegate_->LoadAllCredentialsIntoMemory(tokens);
+
+ EXPECT_EQ(1u, oauth2_service_delegate_->GetAccounts().size());
+ EXPECT_TRUE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable("foobar@gmail.com"));
+ EXPECT_STREQ(
+ "good_token",
+ oauth2_service_delegate_->GetRefreshToken("foobar@gmail.com").c_str());
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, ShutdownService) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kMirror);
+ EXPECT_TRUE(oauth2_service_delegate_->GetAccounts().empty());
+ oauth2_service_delegate_->UpdateCredentials("account_id1", "refresh_token1");
+ oauth2_service_delegate_->UpdateCredentials("account_id2", "refresh_token2");
+ std::vector<std::string> accounts = oauth2_service_delegate_->GetAccounts();
+ EXPECT_EQ(2u, accounts.size());
+ EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id1"));
+ EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id2"));
+ oauth2_service_delegate_->LoadCredentials("account_id1");
+ oauth2_service_delegate_->UpdateCredentials("account_id1", "refresh_token3");
+ oauth2_service_delegate_->Shutdown();
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+ EXPECT_TRUE(oauth2_service_delegate_->refresh_tokens_.empty());
+ EXPECT_EQ(0, oauth2_service_delegate_->web_data_service_request_);
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, GaiaIdMigration) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kMirror);
+ if (account_tracker_service_.GetMigrationState() !=
+ AccountTrackerService::MIGRATION_NOT_STARTED) {
+ std::string email = "foo@gmail.com";
+ std::string gaia_id = "foo's gaia id";
+
+ pref_service_.SetInteger(prefs::kAccountIdMigrationState,
+ AccountTrackerService::MIGRATION_NOT_STARTED);
+
+ ListPrefUpdate update(&pref_service_, prefs::kAccountInfo);
+ update->Clear();
+ auto dict = std::make_unique<base::DictionaryValue>();
+ dict->SetString("account_id", email);
+ dict->SetString("email", email);
+ dict->SetString("gaia", gaia_id);
+ update->Append(std::move(dict));
+ account_tracker_service_.Shutdown();
+ account_tracker_service_.Initialize(&pref_service_, base::FilePath());
+
+ AddAuthTokenManually("AccountId-" + email, "refresh_token");
+ oauth2_service_delegate_->LoadCredentials(gaia_id);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(1, token_available_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+
+ std::vector<std::string> accounts = oauth2_service_delegate_->GetAccounts();
+ EXPECT_EQ(1u, accounts.size());
+
+ EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(email));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(gaia_id));
+
+ account_tracker_service_.SetMigrationDone();
+ oauth2_service_delegate_->Shutdown();
+ ResetObserverCounts();
+
+ oauth2_service_delegate_->LoadCredentials(gaia_id);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(1, token_available_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+
+ EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(email));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(gaia_id));
+ accounts = oauth2_service_delegate_->GetAccounts();
+ EXPECT_EQ(1u, accounts.size());
+ }
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ GaiaIdMigrationCrashInTheMiddle) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kMirror);
+ if (account_tracker_service_.GetMigrationState() !=
+ AccountTrackerService::MIGRATION_NOT_STARTED) {
+ std::string email1 = "foo@gmail.com";
+ std::string gaia_id1 = "foo's gaia id";
+ std::string email2 = "bar@gmail.com";
+ std::string gaia_id2 = "bar's gaia id";
+
+ pref_service_.SetInteger(prefs::kAccountIdMigrationState,
+ AccountTrackerService::MIGRATION_NOT_STARTED);
+
+ ListPrefUpdate update(&pref_service_, prefs::kAccountInfo);
+ update->Clear();
+ auto dict = std::make_unique<base::DictionaryValue>();
+ dict->SetString("account_id", email1);
+ dict->SetString("email", email1);
+ dict->SetString("gaia", gaia_id1);
+ update->Append(std::move(dict));
+ dict = std::make_unique<base::DictionaryValue>();
+ dict->SetString("account_id", email2);
+ dict->SetString("email", email2);
+ dict->SetString("gaia", gaia_id2);
+ update->Append(std::move(dict));
+ account_tracker_service_.Shutdown();
+ account_tracker_service_.Initialize(&pref_service_, base::FilePath());
+
+ AddAuthTokenManually("AccountId-" + email1, "refresh_token");
+ AddAuthTokenManually("AccountId-" + email2, "refresh_token");
+ AddAuthTokenManually("AccountId-" + gaia_id1, "refresh_token");
+ oauth2_service_delegate_->LoadCredentials(gaia_id1);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(2, token_available_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+
+ std::vector<std::string> accounts = oauth2_service_delegate_->GetAccounts();
+ EXPECT_EQ(2u, accounts.size());
+
+ EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(email1));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(gaia_id1));
+ EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(email2));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(gaia_id2));
+
+ account_tracker_service_.SetMigrationDone();
+ oauth2_service_delegate_->Shutdown();
+ ResetObserverCounts();
+
+ oauth2_service_delegate_->LoadCredentials(gaia_id1);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(2, token_available_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+
+ EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(email1));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(gaia_id1));
+ EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable(email2));
+ EXPECT_TRUE(oauth2_service_delegate_->RefreshTokenIsAvailable(gaia_id2));
+ accounts = oauth2_service_delegate_->GetAccounts();
+ EXPECT_EQ(2u, accounts.size());
+ }
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ LoadPrimaryAccountOnlyWhenAccountConsistencyDisabled) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ std::string primary_account = "primaryaccount";
+ std::string secondary_account = "secondaryaccount";
+
+ oauth2_service_delegate_->RevokeAllCredentials();
+ ResetObserverCounts();
+ AddAuthTokenManually("AccountId-" + primary_account, "refresh_token");
+ AddAuthTokenManually("AccountId-" + secondary_account, "refresh_token");
+ oauth2_service_delegate_->LoadCredentials(primary_account);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(1, token_available_count_);
+ EXPECT_EQ(1, token_revoked_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_TRUE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable(primary_account));
+ EXPECT_FALSE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable(secondary_account));
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ LoadSecondaryAccountsWhenMirrorEnabled) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kMirror);
+ std::string primary_account = "primaryaccount";
+ std::string secondary_account = "secondaryaccount";
+
+ oauth2_service_delegate_->RevokeAllCredentials();
+ ResetObserverCounts();
+ AddAuthTokenManually("AccountId-" + primary_account, "refresh_token");
+ AddAuthTokenManually("AccountId-" + secondary_account, "refresh_token");
+ oauth2_service_delegate_->LoadCredentials(primary_account);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(2, token_available_count_);
+ EXPECT_EQ(0, token_revoked_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_TRUE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable(primary_account));
+ EXPECT_TRUE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable(secondary_account));
+}
+
+// Regression test for https://crbug.com/823707
+// Checks that OnAuthErrorChanged() is called during UpdateCredentials(), and
+// that RefreshTokenIsAvailable() can be used at this time.
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, OnAuthErrorChanged) {
+ class TokenServiceErrorObserver : public OAuth2TokenService::Observer {
+ public:
+ explicit TokenServiceErrorObserver(
+ MutableProfileOAuth2TokenServiceDelegate* delegate)
+ : delegate_(delegate) {}
+
+ void OnAuthErrorChanged(const std::string& account_id,
+ const GoogleServiceAuthError& auth_error) override {
+ error_changed_ = true;
+ EXPECT_EQ("account_id", account_id);
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(), auth_error);
+ EXPECT_TRUE(delegate_->RefreshTokenIsAvailable("account_id"));
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ delegate_->GetAuthError("account_id"));
+ }
+
+ MutableProfileOAuth2TokenServiceDelegate* delegate_;
+ bool error_changed_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(TokenServiceErrorObserver);
+ };
+
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+
+ // Start with the SigninErrorController in error state, so that it calls
+ // OnErrorChanged() from AddProvider().
+ oauth2_service_delegate_->UpdateCredentials(
+ "error_account_id",
+ MutableProfileOAuth2TokenServiceDelegate::kInvalidRefreshToken);
+
+ TokenServiceErrorObserver token_service_observer(
+ oauth2_service_delegate_.get());
+ oauth2_service_delegate_->AddObserver(&token_service_observer);
+
+ ASSERT_FALSE(token_service_observer.error_changed_);
+ oauth2_service_delegate_->UpdateCredentials("account_id", "token");
+ EXPECT_TRUE(token_service_observer.error_changed_);
+
+ oauth2_service_delegate_->RemoveObserver(&token_service_observer);
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, GetAuthError) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ // Accounts have no error by default.
+ oauth2_service_delegate_->UpdateCredentials("account_id", "refresh_token");
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ oauth2_service_delegate_->GetAuthError("account_id"));
+ // Update the error.
+ GoogleServiceAuthError error =
+ GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_SERVER);
+ oauth2_service_delegate_->UpdateAuthError("account_id", error);
+ EXPECT_EQ(error, oauth2_service_delegate_->GetAuthError("account_id"));
+ // Unknown account has no error.
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ oauth2_service_delegate_->GetAuthError("foo"));
+ // Add account with invalid token.
+ oauth2_service_delegate_->UpdateCredentials(
+ "account_id_2",
+ MutableProfileOAuth2TokenServiceDelegate::kInvalidRefreshToken);
+ EXPECT_EQ(GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_CLIENT),
+ oauth2_service_delegate_->GetAuthError("account_id_2"));
+}
+
+// Checks that OnAuthErrorChanged() is called before OnRefreshTokenAvailable,
+// and that the error state is correctly available from within both calls.
+// Regression test for https://crbug.com/824791.
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ InvalidTokenObserverCallsOrdering) {
+ class TokenServiceErrorObserver : public OAuth2TokenService::Observer {
+ public:
+ explicit TokenServiceErrorObserver(
+ MutableProfileOAuth2TokenServiceDelegate* delegate)
+ : delegate_(delegate) {}
+
+ void OnAuthErrorChanged(const std::string& account_id,
+ const GoogleServiceAuthError& auth_error) override {
+ error_changed_ = true;
+ EXPECT_FALSE(token_available_)
+ << "OnAuthErrorChanged() should be called first";
+ EXPECT_EQ(auth_error, delegate_->GetAuthError(account_id));
+ CheckTokenState(account_id);
+ }
+
+ void OnRefreshTokenAvailable(const std::string& account_id) override {
+ token_available_ = true;
+ EXPECT_TRUE(error_changed_)
+ << "OnAuthErrorChanged() should be called first";
+ CheckTokenState(account_id);
+ }
+
+ void CheckTokenState(const std::string& account_id) {
+ EXPECT_EQ("account_id", account_id);
+ EXPECT_TRUE(delegate_->RefreshTokenIsAvailable("account_id"));
+ EXPECT_EQ(GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_CLIENT),
+ delegate_->GetAuthError("account_id"));
+ }
+
+ MutableProfileOAuth2TokenServiceDelegate* delegate_;
+ bool error_changed_ = false;
+ bool token_available_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(TokenServiceErrorObserver);
+ };
+
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ TokenServiceErrorObserver token_service_observer(
+ oauth2_service_delegate_.get());
+ oauth2_service_delegate_->AddObserver(&token_service_observer);
+ oauth2_service_delegate_->UpdateCredentials(
+ "account_id",
+ MutableProfileOAuth2TokenServiceDelegate::kInvalidRefreshToken);
+ EXPECT_TRUE(token_service_observer.token_available_);
+ EXPECT_TRUE(token_service_observer.error_changed_);
+ oauth2_service_delegate_->RemoveObserver(&token_service_observer);
+}
+
+// Checks that set_revoke_all_tokens_on_first_load() revokes the tokens,
+// updates the database, and is applied only once.
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, ClearTokensOnStartup) {
+ client_->SetNetworkCallsDelayed(true);
+ revoke_all_tokens_on_load_ = true;
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled);
+ std::string primary_account = "primaryaccount";
+ std::string secondary_account = "secondaryaccount";
+
+ oauth2_service_delegate_->RevokeAllCredentials();
+ ResetObserverCounts();
+ AddAuthTokenManually("AccountId-" + primary_account, "refresh_token");
+ AddAuthTokenManually("AccountId-" + secondary_account, "refresh_token");
+ oauth2_service_delegate_->LoadCredentials(primary_account);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(1, tokens_loaded_count_);
+ EXPECT_EQ(1, token_available_count_);
+ EXPECT_EQ(1, token_revoked_count_);
+ EXPECT_EQ(1, start_batch_changes_);
+ EXPECT_EQ(1, end_batch_changes_);
+ EXPECT_TRUE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable(primary_account));
+ EXPECT_FALSE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable(secondary_account));
+ EXPECT_STREQ(
+ MutableProfileOAuth2TokenServiceDelegate::kInvalidRefreshToken,
+ oauth2_service_delegate_->GetRefreshToken(primary_account).c_str());
+ EXPECT_EQ(GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_CLIENT),
+ oauth2_service_delegate_->GetAuthError(primary_account));
+
+ // Tokens are revoked on the server.
+ EXPECT_EQ(2u, oauth2_service_delegate_->server_revokes_.size());
+ client_->SetNetworkCallsDelayed(false);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+
+ // Check that the changes have been persisted in the database: tokens are not
+ // revoked again on the server.
+ client_->SetNetworkCallsDelayed(true);
+ oauth2_service_delegate_->LoadCredentials(primary_account);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable(primary_account));
+ EXPECT_FALSE(
+ oauth2_service_delegate_->RefreshTokenIsAvailable(secondary_account));
+ EXPECT_STREQ(
+ MutableProfileOAuth2TokenServiceDelegate::kInvalidRefreshToken,
+ oauth2_service_delegate_->GetRefreshToken(primary_account).c_str());
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+}
+
+// Tests that ProfileOAuthTokenService refresh token operations correctly pass
+// the source when used with a |MutableProfileOAuth2TokenServiceDelegate|
+// delegate.
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
+ SourceForRefreshTokenOperations) {
+ using Source = signin_metrics::SourceForRefreshTokenOperation;
+
+ ProfileOAuth2TokenService::RegisterProfilePrefs(pref_service_.registry());
+ ProfileOAuth2TokenService token_service(
+ &pref_service_,
+ CreateOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDisabled));
+ token_service.AddDiagnosticsObserver(this);
+
+ {
+ base::HistogramTester h_tester;
+ AddAuthTokenManually("account_id", "refresh_token");
+ token_service.LoadCredentials("account_id");
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ("TokenService::LoadCredentials",
+ source_for_refresh_token_available_);
+ h_tester.ExpectUniqueSample(
+ "Signin.RefreshTokenUpdated.ToValidToken.Source",
+ Source::kTokenService_LoadCredentials, 1);
+ }
+
+ {
+ base::HistogramTester h_tester;
+ token_service.UpdateCredentials("account_id", "refresh_token",
+ Source::kSupervisedUser_InitSync);
+ EXPECT_EQ("SupervisedUser::InitSync", source_for_refresh_token_available_);
+ h_tester.ExpectUniqueSample(
+ "Signin.RefreshTokenUpdated.ToValidToken.Source",
+ Source::kSupervisedUser_InitSync, 1);
+
+ token_service.RevokeCredentials(
+ "account_id", Source::kAccountReconcilor_GaiaCookiesUpdated);
+ EXPECT_EQ("AccountReconcilor::GaiaCookiesUpdated",
+ source_for_refresh_token_revoked_);
+ h_tester.ExpectUniqueSample("Signin.RefreshTokenRevoked.Source",
+ Source::kAccountReconcilor_GaiaCookiesUpdated,
+ 1);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ {
+ base::HistogramTester h_tester;
+ token_service.UpdateCredentials("account_id_1", "refresh_token",
+ Source::kDiceResponseHandler_Signin);
+ EXPECT_EQ("DiceResponseHandler::Signin",
+ source_for_refresh_token_available_);
+ h_tester.ExpectUniqueSample(
+ "Signin.RefreshTokenUpdated.ToValidToken.Source",
+ Source::kDiceResponseHandler_Signin, 1);
+
+ token_service.UpdateCredentials(
+ "account_id_2", OAuth2TokenServiceDelegate::kInvalidRefreshToken,
+ Source::kDiceResponseHandler_Signin);
+ EXPECT_EQ("DiceResponseHandler::Signin",
+ source_for_refresh_token_available_);
+ h_tester.ExpectUniqueSample(
+ "Signin.RefreshTokenUpdated.ToInvalidToken.Source",
+ Source::kDiceResponseHandler_Signin, 1);
+
+ token_service.RevokeAllCredentials(Source::kDiceResponseHandler_Signout);
+ EXPECT_EQ("DiceResponseHandler::Signout",
+ source_for_refresh_token_revoked_);
+ h_tester.ExpectUniqueSample("Signin.RefreshTokenRevoked.Source",
+ Source::kDiceResponseHandler_Signout, 2);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ token_service.RemoveDiagnosticsObserver(this);
+ token_service.Shutdown();
+}
+
+TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, ExtractCredentials) {
+ InitializeOAuth2ServiceDelegate(signin::AccountConsistencyMethod::kDice);
+ oauth2_service_delegate_->LoadCredentials(std::string());
+
+ // Create another token service
+ sync_preferences::TestingPrefServiceSyncable prefs;
+ ProfileOAuth2TokenService::RegisterProfilePrefs(prefs.registry());
+ std::unique_ptr<FakeOAuth2TokenServiceDelegate> delegate =
+ std::make_unique<FakeOAuth2TokenServiceDelegate>();
+ FakeOAuth2TokenServiceDelegate* other_delegate = delegate.get();
+ ProfileOAuth2TokenService other_token_service(&prefs, std::move(delegate));
+ other_token_service.LoadCredentials(std::string());
+
+ // Add credentials to the first token service delegate.
+ oauth2_service_delegate_->UpdateCredentials("account_id", "token");
+
+ // Extract the credentials.
+ ResetObserverCounts();
+ oauth2_service_delegate_->ExtractCredentials(&other_token_service,
+ "account_id");
+
+ EXPECT_EQ(1, token_revoked_count_);
+ EXPECT_TRUE(oauth2_service_delegate_->server_revokes_.empty());
+ EXPECT_FALSE(oauth2_service_delegate_->RefreshTokenIsAvailable("account_id"));
+ EXPECT_TRUE(other_delegate->RefreshTokenIsAvailable("account_id"));
+ EXPECT_EQ("token", other_delegate->GetRefreshToken("account_id"));
+}
diff --git a/chromium/components/signin/core/browser/oauth2_token_service_delegate_android.cc b/chromium/components/signin/core/browser/oauth2_token_service_delegate_android.cc
new file mode 100644
index 00000000000..0d872ed9d62
--- /dev/null
+++ b/chromium/components/signin/core/browser/oauth2_token_service_delegate_android.cc
@@ -0,0 +1,529 @@
+// Copyright 2013 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 "components/signin/core/browser/oauth2_token_service_delegate_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
+#include "components/signin/core/browser/account_info.h"
+#include "google_apis/gaia/gaia_auth_util.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher.h"
+#include "jni/OAuth2TokenService_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
+using base::android::JavaRef;
+using base::android::ScopedJavaLocalRef;
+
+namespace {
+
+// Callback from FetchOAuth2TokenWithUsername().
+// Arguments:
+// - the error, or NONE if the token fetch was successful.
+// - the OAuth2 access token.
+// - the expiry time of the token (may be null, indicating that the expiry
+// time is unknown.
+typedef base::Callback<
+ void(const GoogleServiceAuthError&, const std::string&, const base::Time&)>
+ FetchOAuth2TokenCallback;
+
+class AndroidAccessTokenFetcher : public OAuth2AccessTokenFetcher {
+ public:
+ AndroidAccessTokenFetcher(OAuth2AccessTokenConsumer* consumer,
+ const std::string& account_id);
+ ~AndroidAccessTokenFetcher() override;
+
+ // Overrides from OAuth2AccessTokenFetcher:
+ void Start(const std::string& client_id,
+ const std::string& client_secret,
+ const std::vector<std::string>& scopes) override;
+ void CancelRequest() override;
+
+ // Handles an access token response.
+ void OnAccessTokenResponse(const GoogleServiceAuthError& error,
+ const std::string& access_token,
+ const base::Time& expiration_time);
+
+ private:
+ std::string CombineScopes(const std::vector<std::string>& scopes);
+
+ std::string account_id_;
+ bool request_was_cancelled_;
+ base::WeakPtrFactory<AndroidAccessTokenFetcher> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(AndroidAccessTokenFetcher);
+};
+
+AndroidAccessTokenFetcher::AndroidAccessTokenFetcher(
+ OAuth2AccessTokenConsumer* consumer,
+ const std::string& account_id)
+ : OAuth2AccessTokenFetcher(consumer),
+ account_id_(account_id),
+ request_was_cancelled_(false),
+ weak_factory_(this) {}
+
+AndroidAccessTokenFetcher::~AndroidAccessTokenFetcher() {}
+
+void AndroidAccessTokenFetcher::Start(const std::string& client_id,
+ const std::string& client_secret,
+ const std::vector<std::string>& scopes) {
+ JNIEnv* env = AttachCurrentThread();
+ std::string scope = CombineScopes(scopes);
+ ScopedJavaLocalRef<jstring> j_username =
+ ConvertUTF8ToJavaString(env, account_id_);
+ ScopedJavaLocalRef<jstring> j_scope = ConvertUTF8ToJavaString(env, scope);
+ std::unique_ptr<FetchOAuth2TokenCallback> heap_callback(
+ new FetchOAuth2TokenCallback(
+ base::Bind(&AndroidAccessTokenFetcher::OnAccessTokenResponse,
+ weak_factory_.GetWeakPtr())));
+
+ // Call into Java to get a new token.
+ Java_OAuth2TokenService_getAccessTokenFromNative(
+ env, j_username, j_scope,
+ reinterpret_cast<intptr_t>(heap_callback.release()));
+}
+
+void AndroidAccessTokenFetcher::CancelRequest() {
+ request_was_cancelled_ = true;
+}
+
+void AndroidAccessTokenFetcher::OnAccessTokenResponse(
+ const GoogleServiceAuthError& error,
+ const std::string& access_token,
+ const base::Time& expiration_time) {
+ if (request_was_cancelled_) {
+ // Ignore the callback if the request was cancelled.
+ return;
+ }
+ if (error.state() == GoogleServiceAuthError::NONE) {
+ FireOnGetTokenSuccess(OAuth2AccessTokenConsumer::TokenResponse(
+ access_token, expiration_time, std::string()));
+ } else {
+ FireOnGetTokenFailure(error);
+ }
+}
+
+// static
+std::string AndroidAccessTokenFetcher::CombineScopes(
+ const std::vector<std::string>& scopes) {
+ // The Android AccountManager supports multiple scopes separated by a space:
+ // https://code.google.com/p/google-api-java-client/wiki/OAuth2#Android
+ std::string scope;
+ for (std::vector<std::string>::const_iterator it = scopes.begin();
+ it != scopes.end(); ++it) {
+ if (!scope.empty())
+ scope += " ";
+ scope += *it;
+ }
+ return scope;
+}
+
+} // namespace
+
+bool OAuth2TokenServiceDelegateAndroid::is_testing_profile_ = false;
+
+OAuth2TokenServiceDelegateAndroid::OAuth2TokenServiceDelegateAndroid(
+ AccountTrackerService* account_tracker_service)
+ : account_tracker_service_(account_tracker_service),
+ fire_refresh_token_loaded_(RT_LOAD_NOT_START) {
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ctor";
+ DCHECK(account_tracker_service_);
+ JNIEnv* env = AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jobject> local_java_ref =
+ Java_OAuth2TokenService_create(env, reinterpret_cast<intptr_t>(this),
+ account_tracker_service_->GetJavaObject());
+ java_ref_.Reset(env, local_java_ref.obj());
+
+ if (account_tracker_service_->GetMigrationState() ==
+ AccountTrackerService::MIGRATION_IN_PROGRESS) {
+ std::vector<std::string> accounts = GetAccounts();
+ std::vector<std::string> accounts_id;
+ for (auto account_name : accounts) {
+ AccountInfo account_info =
+ account_tracker_service_->FindAccountInfoByEmail(account_name);
+ DCHECK(!account_info.gaia.empty());
+ accounts_id.push_back(account_info.gaia);
+ }
+ ScopedJavaLocalRef<jobjectArray> java_accounts(
+ base::android::ToJavaArrayOfStrings(env, accounts_id));
+ Java_OAuth2TokenService_saveStoredAccounts(env, java_accounts);
+ }
+
+ if (!is_testing_profile_) {
+ Java_OAuth2TokenService_validateAccounts(AttachCurrentThread(), java_ref_,
+ JNI_TRUE);
+ }
+}
+
+OAuth2TokenServiceDelegateAndroid::~OAuth2TokenServiceDelegateAndroid() {}
+
+ScopedJavaLocalRef<jobject> OAuth2TokenServiceDelegateAndroid::GetJavaObject() {
+ return ScopedJavaLocalRef<jobject>(java_ref_);
+}
+
+bool OAuth2TokenServiceDelegateAndroid::RefreshTokenIsAvailable(
+ const std::string& account_id) const {
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::RefreshTokenIsAvailable"
+ << " account= " << account_id;
+ std::string account_name = MapAccountIdToAccountName(account_id);
+ if (account_name.empty()) {
+ // This corresponds to the case when the account with id |account_id| is not
+ // present on the device and thus was not seeded.
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::RefreshTokenIsAvailable"
+ << " cannot find account name for account id " << account_id;
+ return false;
+ }
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> j_account_id =
+ ConvertUTF8ToJavaString(env, account_name);
+ jboolean refresh_token_is_available =
+ Java_OAuth2TokenService_hasOAuth2RefreshToken(env, j_account_id);
+ return refresh_token_is_available == JNI_TRUE;
+}
+
+GoogleServiceAuthError OAuth2TokenServiceDelegateAndroid::GetAuthError(
+ const std::string& account_id) const {
+ auto it = errors_.find(account_id);
+ return (it == errors_.end()) ? GoogleServiceAuthError::AuthErrorNone()
+ : it->second;
+}
+
+void OAuth2TokenServiceDelegateAndroid::UpdateAuthError(
+ const std::string& account_id,
+ const GoogleServiceAuthError& error) {
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::UpdateAuthError"
+ << " account=" << account_id << " error=" << error.ToString();
+
+ if (error.IsTransientError())
+ return;
+
+ auto it = errors_.find(account_id);
+ if (error.state() == GoogleServiceAuthError::NONE) {
+ if (it == errors_.end())
+ return;
+ errors_.erase(it);
+ } else {
+ if (it != errors_.end() && it->second == error)
+ return;
+ errors_[account_id] = error;
+ }
+ FireAuthErrorChanged(account_id, error);
+}
+
+std::vector<std::string> OAuth2TokenServiceDelegateAndroid::GetAccounts() {
+ std::vector<std::string> accounts;
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobjectArray> j_accounts =
+ Java_OAuth2TokenService_getAccounts(env);
+ // TODO(fgorski): We may decide to filter out some of the accounts.
+ base::android::AppendJavaStringArrayToStringVector(env, j_accounts,
+ &accounts);
+ return accounts;
+}
+
+std::vector<std::string>
+OAuth2TokenServiceDelegateAndroid::GetSystemAccountNames() {
+ std::vector<std::string> account_names;
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobjectArray> j_accounts =
+ Java_OAuth2TokenService_getSystemAccountNames(env);
+ base::android::AppendJavaStringArrayToStringVector(env, j_accounts,
+ &account_names);
+ return account_names;
+}
+
+OAuth2AccessTokenFetcher*
+OAuth2TokenServiceDelegateAndroid::CreateAccessTokenFetcher(
+ const std::string& account_id,
+ scoped_refptr<network::SharedURLLoaderFactory> url_factory,
+ OAuth2AccessTokenConsumer* consumer) {
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::CreateAccessTokenFetcher"
+ << " account= " << account_id;
+ ValidateAccountId(account_id);
+ std::string account_name = MapAccountIdToAccountName(account_id);
+ DCHECK(!account_name.empty())
+ << "Cannot find account name for account id " << account_id;
+ return new AndroidAccessTokenFetcher(consumer, account_name);
+}
+
+void OAuth2TokenServiceDelegateAndroid::InvalidateAccessToken(
+ const std::string& account_id,
+ const std::string& client_id,
+ const OAuth2TokenService::ScopeSet& scopes,
+ const std::string& access_token) {
+ ValidateAccountId(account_id);
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> j_access_token =
+ ConvertUTF8ToJavaString(env, access_token);
+ Java_OAuth2TokenService_invalidateAccessToken(env, j_access_token);
+}
+
+void OAuth2TokenServiceDelegateAndroid::ValidateAccounts(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& obj,
+ const JavaParamRef<jstring>& j_current_acc,
+ jboolean j_force_notifications) {
+ std::string signed_in_account_name;
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts from java";
+ if (j_current_acc)
+ signed_in_account_name = ConvertJavaStringToUTF8(env, j_current_acc);
+ if (!signed_in_account_name.empty())
+ signed_in_account_name = gaia::CanonicalizeEmail(signed_in_account_name);
+
+ // Clear any auth errors so that client can retry to get access tokens.
+ errors_.clear();
+
+ ValidateAccounts(MapAccountNameToAccountId(signed_in_account_name),
+ j_force_notifications != JNI_FALSE);
+}
+
+void OAuth2TokenServiceDelegateAndroid::ValidateAccounts(
+ const std::string& signed_in_account_id,
+ bool force_notifications) {
+ std::vector<std::string> curr_ids;
+ for (const std::string& curr_name : GetSystemAccountNames()) {
+ std::string curr_id(MapAccountNameToAccountId(curr_name));
+ if (!curr_id.empty())
+ curr_ids.push_back(curr_id);
+ }
+
+ std::vector<std::string> prev_ids;
+ for (const std::string& prev_id : GetAccounts()) {
+ if (ValidateAccountId(prev_id))
+ prev_ids.push_back(prev_id);
+ }
+
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts:"
+ << " sigined_in_account_id=" << signed_in_account_id
+ << " prev_ids=" << prev_ids.size() << " curr_ids=" << curr_ids.size()
+ << " force=" << (force_notifications ? "true" : "false");
+
+ std::vector<std::string> refreshed_ids;
+ std::vector<std::string> revoked_ids;
+ bool currently_signed_in =
+ ValidateAccounts(signed_in_account_id, prev_ids, curr_ids, &refreshed_ids,
+ &revoked_ids, force_notifications);
+
+ ScopedBatchChange batch(this);
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobjectArray> java_accounts;
+ if (currently_signed_in) {
+ java_accounts = base::android::ToJavaArrayOfStrings(env, curr_ids);
+ } else {
+ java_accounts =
+ base::android::ToJavaArrayOfStrings(env, std::vector<std::string>());
+ }
+
+ // Save the current accounts in the token service before calling
+ // FireRefreshToken* methods.
+ Java_OAuth2TokenService_saveStoredAccounts(env, java_accounts);
+
+ for (const std::string& refreshed_id : refreshed_ids)
+ FireRefreshTokenAvailable(refreshed_id);
+ for (const std::string& revoked_id : revoked_ids)
+ FireRefreshTokenRevoked(revoked_id);
+ if (fire_refresh_token_loaded_ == RT_WAIT_FOR_VALIDATION) {
+ fire_refresh_token_loaded_ = RT_LOADED;
+ FireRefreshTokensLoaded();
+ } else if (fire_refresh_token_loaded_ == RT_LOAD_NOT_START) {
+ fire_refresh_token_loaded_ = RT_HAS_BEEN_VALIDATED;
+ }
+
+ // Clear accounts no longer exist on device from AccountTrackerService.
+ std::vector<AccountInfo> accounts_info =
+ account_tracker_service_->GetAccounts();
+ for (const AccountInfo& info : accounts_info) {
+ if (!base::ContainsValue(curr_ids, info.account_id))
+ account_tracker_service_->RemoveAccount(info.account_id);
+ }
+
+ // No need to wait for SigninManager to finish migration if not signed in.
+ if (account_tracker_service_->GetMigrationState() ==
+ AccountTrackerService::MIGRATION_IN_PROGRESS &&
+ signed_in_account_id.empty()) {
+ account_tracker_service_->SetMigrationDone();
+ }
+}
+
+bool OAuth2TokenServiceDelegateAndroid::ValidateAccounts(
+ const std::string& signed_in_id,
+ const std::vector<std::string>& prev_ids,
+ const std::vector<std::string>& curr_ids,
+ std::vector<std::string>* refreshed_ids,
+ std::vector<std::string>* revoked_ids,
+ bool force_notifications) {
+ bool currently_signed_in = base::ContainsValue(curr_ids, signed_in_id);
+ if (currently_signed_in) {
+ // Revoke token for ids that have been removed from the device.
+ for (const std::string& prev_id : prev_ids) {
+ if (prev_id == signed_in_id)
+ continue;
+ if (!base::ContainsValue(curr_ids, prev_id)) {
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts:"
+ << "revoked=" << prev_id;
+ revoked_ids->push_back(prev_id);
+ }
+ }
+
+ // Refresh token for new ids or all ids if |force_notifications|.
+ if (force_notifications || !base::ContainsValue(prev_ids, signed_in_id)) {
+ // Always fire the primary signed in account first.
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts:"
+ << "refreshed=" << signed_in_id;
+ refreshed_ids->push_back(signed_in_id);
+ }
+ for (const std::string& curr_id : curr_ids) {
+ if (curr_id == signed_in_id)
+ continue;
+ if (force_notifications || !base::ContainsValue(prev_ids, curr_id)) {
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts:"
+ << "refreshed=" << curr_id;
+ refreshed_ids->push_back(curr_id);
+ }
+ }
+ } else {
+ if (base::ContainsValue(prev_ids, signed_in_id)) {
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts:"
+ << "revoked=" << signed_in_id;
+ revoked_ids->push_back(signed_in_id);
+ }
+ for (const std::string& prev_id : prev_ids) {
+ if (prev_id == signed_in_id)
+ continue;
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::ValidateAccounts:"
+ << "revoked=" << prev_id;
+ revoked_ids->push_back(prev_id);
+ }
+ }
+ return currently_signed_in;
+}
+
+void OAuth2TokenServiceDelegateAndroid::FireRefreshTokenAvailable(
+ const std::string& account_id) {
+ DCHECK(!account_id.empty());
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::FireRefreshTokenAvailable id="
+ << account_id;
+ std::string account_name = MapAccountIdToAccountName(account_id);
+ DCHECK(!account_name.empty())
+ << "Cannot find account name for account id " << account_id;
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> j_account_name =
+ ConvertUTF8ToJavaString(env, account_name);
+ Java_OAuth2TokenService_notifyRefreshTokenAvailable(env, java_ref_,
+ j_account_name);
+ OAuth2TokenServiceDelegate::FireRefreshTokenAvailable(account_id);
+}
+
+void OAuth2TokenServiceDelegateAndroid::FireRefreshTokenRevoked(
+ const std::string& account_id) {
+ DCHECK(!account_id.empty());
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::FireRefreshTokenRevoked id="
+ << account_id;
+ std::string account_name = MapAccountIdToAccountName(account_id);
+ if (!account_name.empty()) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> j_account_name =
+ ConvertUTF8ToJavaString(env, account_name);
+ Java_OAuth2TokenService_notifyRefreshTokenRevoked(env, java_ref_,
+ j_account_name);
+ } else {
+ // Current prognosis is that we have an unmigrated account which is due for
+ // deletion. Record a histogram to debug this.
+ UMA_HISTOGRAM_ENUMERATION("OAuth2Login.AccountRevoked.MigrationState",
+ account_tracker_service_->GetMigrationState(),
+ AccountTrackerService::NUM_MIGRATION_STATES);
+ bool is_email_id = account_id.find('@') != std::string::npos;
+ UMA_HISTOGRAM_BOOLEAN("OAuth2Login.AccountRevoked.IsEmailId", is_email_id);
+ }
+ OAuth2TokenServiceDelegate::FireRefreshTokenRevoked(account_id);
+}
+
+void OAuth2TokenServiceDelegateAndroid::FireRefreshTokensLoaded() {
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::FireRefreshTokensLoaded";
+
+ DCHECK_EQ(LOAD_CREDENTIALS_IN_PROGRESS, load_credentials_state());
+ set_load_credentials_state(LOAD_CREDENTIALS_FINISHED_WITH_SUCCESS);
+
+ JNIEnv* env = AttachCurrentThread();
+ Java_OAuth2TokenService_notifyRefreshTokensLoaded(env, java_ref_);
+ OAuth2TokenServiceDelegate::FireRefreshTokensLoaded();
+}
+
+void OAuth2TokenServiceDelegateAndroid::RevokeAllCredentials() {
+ DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::RevokeAllCredentials";
+ ScopedBatchChange batch(this);
+ std::vector<std::string> accounts_to_revoke = GetAccounts();
+
+ // Clear accounts in the token service before calling
+ // |FireRefreshTokenRevoked|.
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobjectArray> java_accounts(
+ base::android::ToJavaArrayOfStrings(env, std::vector<std::string>()));
+ Java_OAuth2TokenService_saveStoredAccounts(env, java_accounts);
+
+ for (const std::string& account : accounts_to_revoke)
+ FireRefreshTokenRevoked(account);
+}
+
+void OAuth2TokenServiceDelegateAndroid::LoadCredentials(
+ const std::string& primary_account_id) {
+ DCHECK_EQ(LOAD_CREDENTIALS_NOT_STARTED, load_credentials_state());
+ set_load_credentials_state(LOAD_CREDENTIALS_IN_PROGRESS);
+ if (primary_account_id.empty()) {
+ FireRefreshTokensLoaded();
+ return;
+ }
+ if (fire_refresh_token_loaded_ == RT_HAS_BEEN_VALIDATED) {
+ fire_refresh_token_loaded_ = RT_LOADED;
+ FireRefreshTokensLoaded();
+ } else if (fire_refresh_token_loaded_ == RT_LOAD_NOT_START) {
+ fire_refresh_token_loaded_ = RT_WAIT_FOR_VALIDATION;
+ }
+}
+
+std::string OAuth2TokenServiceDelegateAndroid::MapAccountIdToAccountName(
+ const std::string& account_id) const {
+ return account_tracker_service_->GetAccountInfo(account_id).email;
+}
+
+std::string OAuth2TokenServiceDelegateAndroid::MapAccountNameToAccountId(
+ const std::string& account_name) const {
+ std::string account_id =
+ account_tracker_service_->FindAccountInfoByEmail(account_name).account_id;
+ DCHECK(!account_id.empty() || account_name.empty())
+ << "Can't find account id, account_name=" << account_name;
+ return account_id;
+}
+
+// Called from Java when fetching of an OAuth2 token is finished. The
+// |authToken| param is only valid when |result| is true.
+void JNI_OAuth2TokenService_OAuth2TokenFetched(
+ JNIEnv* env,
+ const JavaParamRef<jstring>& authToken,
+ jboolean isTransientError,
+ jlong nativeCallback) {
+ std::string token;
+ if (authToken)
+ token = ConvertJavaStringToUTF8(env, authToken);
+ std::unique_ptr<FetchOAuth2TokenCallback> heap_callback(
+ reinterpret_cast<FetchOAuth2TokenCallback*>(nativeCallback));
+ GoogleServiceAuthError err = GoogleServiceAuthError::AuthErrorNone();
+ if (!authToken) {
+ err =
+ isTransientError
+ ? GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED)
+ : GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_SERVER);
+ }
+ heap_callback->Run(err, token, base::Time());
+}
diff --git a/chromium/components/signin/core/browser/oauth2_token_service_delegate_android.h b/chromium/components/signin/core/browser/oauth2_token_service_delegate_android.h
new file mode 100644
index 00000000000..9ecb1dbbdd3
--- /dev/null
+++ b/chromium/components/signin/core/browser/oauth2_token_service_delegate_android.h
@@ -0,0 +1,132 @@
+// Copyright 2013 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 COMPONENTS_SIGNIN_CORE_BROWSER_OAUTH2_TOKEN_SERVICE_DELEGATE_ANDROID_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_OAUTH2_TOKEN_SERVICE_DELEGATE_ANDROID_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/android/jni_weak_ref.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "google_apis/gaia/oauth2_token_service_delegate.h"
+
+// A specialization of OAuth2TokenServiceDelegate that will be returned by
+// OAuth2TokenServiceDelegateFactory for OS_ANDROID. This instance uses
+// native Android features to lookup OAuth2 tokens.
+//
+// See |OAuth2TokenServiceDelegate| for usage details.
+//
+// Note: requests should be started from the UI thread. To start a
+// request from other thread, please use OAuth2TokenServiceRequest.
+class OAuth2TokenServiceDelegateAndroid : public OAuth2TokenServiceDelegate {
+ public:
+ OAuth2TokenServiceDelegateAndroid(
+ AccountTrackerService* account_tracker_service);
+ ~OAuth2TokenServiceDelegateAndroid() override;
+
+ // Creates a new instance of the OAuth2TokenServiceDelegateAndroid.
+ static OAuth2TokenServiceDelegateAndroid* Create();
+
+ // Returns a reference to the corresponding Java OAuth2TokenService object.
+ base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
+
+ // Called by the TestingProfile class to disable account validation in
+ // tests. This prevents the token service from trying to look up system
+ // accounts which requires special permission.
+ static void set_is_testing_profile() { is_testing_profile_ = true; }
+
+ // OAuth2TokenServiceDelegate overrides:
+ bool RefreshTokenIsAvailable(const std::string& account_id) const override;
+ GoogleServiceAuthError GetAuthError(
+ const std::string& account_id) const override;
+ void UpdateAuthError(const std::string& account_id,
+ const GoogleServiceAuthError& error) override;
+ std::vector<std::string> GetAccounts() override;
+
+ // Lists account names at the OS level.
+ std::vector<std::string> GetSystemAccountNames();
+
+ void ValidateAccounts(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ const base::android::JavaParamRef<jstring>& current_account,
+ jboolean force_notifications);
+
+ // Takes a the signed in sync account as well as all the other
+ // android account ids and check the token status of each. If
+ // |force_notifications| is true, TokenAvailable notifications will
+ // be sent anyway, even if the account was already known.
+ void ValidateAccounts(const std::string& signed_in_account_id,
+ bool force_notifications);
+
+ // Overridden from OAuth2TokenService to complete signout of all
+ // OA2TService aware accounts.
+ void RevokeAllCredentials() override;
+
+ void LoadCredentials(const std::string& primary_account_id) override;
+
+ protected:
+ OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
+ const std::string& account_id,
+ scoped_refptr<network::SharedURLLoaderFactory> url_factory,
+ OAuth2AccessTokenConsumer* consumer) override;
+
+ // Overridden from OAuth2TokenService to intercept token fetch requests and
+ // redirect them to the Account Manager.
+ void InvalidateAccessToken(const std::string& account_id,
+ const std::string& client_id,
+ const OAuth2TokenService::ScopeSet& scopes,
+ const std::string& access_token) override;
+
+ // Called to notify observers when a refresh token is available.
+ void FireRefreshTokenAvailable(const std::string& account_id) override;
+ // Called to notify observers when a refresh token has been revoked.
+ void FireRefreshTokenRevoked(const std::string& account_id) override;
+ // Called to notify observers when refresh tokans have been loaded.
+ void FireRefreshTokensLoaded() override;
+
+ private:
+ std::string MapAccountIdToAccountName(const std::string& account_id) const;
+ std::string MapAccountNameToAccountId(const std::string& account_name) const;
+
+ enum RefreshTokenLoadStatus {
+ RT_LOAD_NOT_START,
+ RT_WAIT_FOR_VALIDATION,
+ RT_HAS_BEEN_VALIDATED,
+ RT_LOADED
+ };
+
+ // Return whether |signed_in_id| is valid and we have access
+ // to all the tokens in |curr_ids|. If |force_notifications| is true,
+ // TokenAvailable notifications will be sent anyway, even if the account was
+ // already known.
+ bool ValidateAccounts(const std::string& signed_in_id,
+ const std::vector<std::string>& prev_ids,
+ const std::vector<std::string>& curr_ids,
+ std::vector<std::string>* refreshed_ids,
+ std::vector<std::string>* revoked_ids,
+ bool force_notifications);
+
+ base::android::ScopedJavaGlobalRef<jobject> java_ref_;
+
+ // Maps account_id to the last error for that account.
+ std::map<std::string, GoogleServiceAuthError> errors_;
+
+ AccountTrackerService* account_tracker_service_;
+ RefreshTokenLoadStatus fire_refresh_token_loaded_;
+
+ static bool is_testing_profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(OAuth2TokenServiceDelegateAndroid);
+};
+
+#endif // CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_DELEGATE_ANDROID_H_
diff --git a/chromium/components/signin/core/browser/profile_oauth2_token_service.cc b/chromium/components/signin/core/browser/profile_oauth2_token_service.cc
index 2384e3367ce..50fb83dd5ce 100644
--- a/chromium/components/signin/core/browser/profile_oauth2_token_service.cc
+++ b/chromium/components/signin/core/browser/profile_oauth2_token_service.cc
@@ -49,6 +49,10 @@ std::string SourceToString(SourceForRefreshTokenOperation source) {
return "DiceResponseHandler::Signout";
case SourceForRefreshTokenOperation::kDiceTurnOnSyncHelper_Abort:
return "DiceTurnOnSyncHelper::Abort";
+ case SourceForRefreshTokenOperation::kMachineLogon_CredentialProvider:
+ return "MachineLogon::CredentialProvider";
+ case SourceForRefreshTokenOperation::kTokenService_ExtractCredentials:
+ return "TokenService::ExtractCredentials";
}
}
} // namespace
@@ -127,6 +131,17 @@ const net::BackoffEntry* ProfileOAuth2TokenService::GetDelegateBackoffEntry() {
return GetDelegate()->BackoffEntry();
}
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+void ProfileOAuth2TokenService::ExtractCredentials(
+ ProfileOAuth2TokenService* to_service,
+ const std::string& account_id) {
+ base::AutoReset<SourceForRefreshTokenOperation> auto_reset(
+ &update_refresh_token_source_,
+ SourceForRefreshTokenOperation::kTokenService_ExtractCredentials);
+ GetDelegate()->ExtractCredentials(to_service, account_id);
+}
+#endif
+
void ProfileOAuth2TokenService::OnRefreshTokenAvailable(
const std::string& account_id) {
// Check if the newly-updated token is valid (invalid tokens are inserted when
diff --git a/chromium/components/signin/core/browser/profile_oauth2_token_service.h b/chromium/components/signin/core/browser/profile_oauth2_token_service.h
index 01866935923..c7c4ae65f87 100644
--- a/chromium/components/signin/core/browser/profile_oauth2_token_service.h
+++ b/chromium/components/signin/core/browser/profile_oauth2_token_service.h
@@ -8,8 +8,9 @@
#include <string>
#include "base/macros.h"
-#include "base/memory/linked_ptr.h"
+#include "build/buildflag.h"
#include "components/keyed_service/core/keyed_service.h"
+#include "components/signin/core/browser/signin_buildflags.h"
#include "components/signin/core/browser/signin_metrics.h"
#include "google_apis/gaia/oauth2_token_service.h"
#include "google_apis/gaia/oauth2_token_service_delegate.h"
@@ -89,6 +90,15 @@ class ProfileOAuth2TokenService : public OAuth2TokenService,
// is no such instance.
const net::BackoffEntry* GetDelegateBackoffEntry();
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+ // Removes the credentials associated to account_id from the internal storage,
+ // and moves them to |to_service|. The credentials are not revoked on the
+ // server, but the OnRefreshTokenRevoked() notification is sent to the
+ // observers.
+ void ExtractCredentials(ProfileOAuth2TokenService* to_service,
+ const std::string& account_id);
+#endif
+
void set_all_credentials_loaded_for_testing(bool loaded) {
all_credentials_loaded_ = loaded;
}
@@ -96,6 +106,7 @@ class ProfileOAuth2TokenService : public OAuth2TokenService,
private:
friend class identity::IdentityManager;
+ // OAuth2TokenService::Observer implementation.
void OnRefreshTokenAvailable(const std::string& account_id) override;
void OnRefreshTokenRevoked(const std::string& account_id) override;
void OnRefreshTokensLoaded() override;
diff --git a/chromium/components/signin/core/browser/signin_error_controller.cc b/chromium/components/signin/core/browser/signin_error_controller.cc
index 305228d7b25..6f1859ea21e 100644
--- a/chromium/components/signin/core/browser/signin_error_controller.cc
+++ b/chromium/components/signin/core/browser/signin_error_controller.cc
@@ -6,45 +6,26 @@
#include "components/signin/core/browser/signin_metrics.h"
-namespace {
-
-typedef std::set<const SigninErrorController::AuthStatusProvider*>
- AuthStatusProviderSet;
-
-} // namespace
-
-SigninErrorController::AuthStatusProvider::AuthStatusProvider() {
-}
-
-SigninErrorController::AuthStatusProvider::~AuthStatusProvider() {
-}
-
-SigninErrorController::SigninErrorController(AccountMode mode)
+SigninErrorController::SigninErrorController(
+ AccountMode mode,
+ identity::IdentityManager* identity_manager)
: account_mode_(mode),
- auth_error_(GoogleServiceAuthError::AuthErrorNone()) {}
+ identity_manager_(identity_manager),
+ scoped_identity_manager_observer_(this),
+ auth_error_(GoogleServiceAuthError::AuthErrorNone()) {
+ DCHECK(identity_manager_);
+ scoped_identity_manager_observer_.Add(identity_manager_);
-SigninErrorController::~SigninErrorController() {
- DCHECK(provider_set_.empty())
- << "All AuthStatusProviders should be unregistered before "
- << "SigninErrorController is destroyed";
+ Update();
}
-void SigninErrorController::AddProvider(const AuthStatusProvider* provider) {
- DCHECK(provider_set_.find(provider) == provider_set_.end())
- << "Adding same AuthStatusProvider multiple times";
- provider_set_.insert(provider);
- AuthStatusChanged();
-}
+SigninErrorController::~SigninErrorController() = default;
-void SigninErrorController::RemoveProvider(const AuthStatusProvider* provider) {
- auto iter = provider_set_.find(provider);
- DCHECK(iter != provider_set_.end())
- << "Removing provider that was never added";
- provider_set_.erase(iter);
- AuthStatusChanged();
+void SigninErrorController::Shutdown() {
+ scoped_identity_manager_observer_.RemoveAll();
}
-void SigninErrorController::AuthStatusChanged() {
+void SigninErrorController::Update() {
GoogleServiceAuthError::State prev_state = auth_error_.state();
std::string prev_account_id = error_account_id_;
bool error_changed = false;
@@ -53,25 +34,33 @@ void SigninErrorController::AuthStatusChanged() {
// actionable error state and some provider exposes a similar error and
// account id, use that error. Otherwise, just take the first actionable
// error we find.
- for (auto it = provider_set_.begin(); it != provider_set_.end(); ++it) {
- std::string account_id = (*it)->GetAccountId();
+ for (const AccountInfo& account_info :
+ identity_manager_->GetAccountsWithRefreshTokens()) {
+ std::string account_id = account_info.account_id;
// In PRIMARY_ACCOUNT mode, ignore all secondary accounts.
if (account_mode_ == AccountMode::PRIMARY_ACCOUNT &&
- (account_id != primary_account_id_)) {
+ (account_id != identity_manager_->GetPrimaryAccountId())) {
continue;
}
- GoogleServiceAuthError error = (*it)->GetAuthStatus();
-
- // Ignore the states we don't want to elevate to the user.
- if (error.state() == GoogleServiceAuthError::NONE ||
- error.IsTransientError()) {
+ if (!identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
+ account_id)) {
continue;
}
+ GoogleServiceAuthError error =
+ identity_manager_->GetErrorStateOfRefreshTokenForAccount(account_id);
+ // IdentityManager only reports persistent errors.
+ DCHECK(error.IsPersistentError());
+
// Prioritize this error if it matches the previous |auth_error_|.
if (error.state() == prev_state && account_id == prev_account_id) {
+ // The previous error for the previous account still exists. This error is
+ // preferred to avoid UI churn, so |auth_error_| and |error_account_id_|
+ // must be updated to match the previous state. This is needed in case
+ // |auth_error_| and |error_account_id_| were updated to other values in
+ // a previous iteration via the if statement below.
auth_error_ = error;
error_account_id_ = account_id;
error_changed = true;
@@ -94,22 +83,23 @@ void SigninErrorController::AuthStatusChanged() {
error_changed = true;
}
- if (error_changed) {
- signin_metrics::LogAuthError(auth_error_);
- for (auto& observer : observer_list_)
- observer.OnErrorChanged();
+ if (!error_changed)
+ return;
+
+ if (auth_error_.state() == prev_state &&
+ error_account_id_ == prev_account_id) {
+ // Only fire notification if the auth error state or account were updated.
+ return;
}
-}
-bool SigninErrorController::HasError() const {
- return auth_error_.state() != GoogleServiceAuthError::NONE &&
- auth_error_.state() != GoogleServiceAuthError::CONNECTION_FAILED;
+ signin_metrics::LogAuthError(auth_error_);
+ for (auto& observer : observer_list_)
+ observer.OnErrorChanged();
}
-void SigninErrorController::SetPrimaryAccountID(const std::string& account_id) {
- primary_account_id_ = account_id;
- if (account_mode_ == AccountMode::PRIMARY_ACCOUNT)
- AuthStatusChanged(); // Recompute the error state.
+bool SigninErrorController::HasError() const {
+ DCHECK(!auth_error_.IsTransientError());
+ return auth_error_.state() != GoogleServiceAuthError::NONE;
}
void SigninErrorController::AddObserver(Observer* observer) {
@@ -119,3 +109,31 @@ void SigninErrorController::AddObserver(Observer* observer) {
void SigninErrorController::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
+
+void SigninErrorController::OnEndBatchOfRefreshTokenStateChanges() {
+ Update();
+}
+
+void SigninErrorController::OnErrorStateOfRefreshTokenUpdatedForAccount(
+ const AccountInfo& account_info,
+ const GoogleServiceAuthError& error) {
+ Update();
+}
+
+void SigninErrorController::OnPrimaryAccountSet(
+ const AccountInfo& primary_account_info) {
+ // Ignore updates to the primary account if not in PRIMARY_ACCOUNT mode.
+ if (account_mode_ != AccountMode::PRIMARY_ACCOUNT)
+ return;
+
+ Update();
+}
+
+void SigninErrorController::OnPrimaryAccountCleared(
+ const AccountInfo& previous_primary_account_info) {
+ // Ignore updates to the primary account if not in PRIMARY_ACCOUNT mode.
+ if (account_mode_ != AccountMode::PRIMARY_ACCOUNT)
+ return;
+
+ Update();
+}
diff --git a/chromium/components/signin/core/browser/signin_error_controller.h b/chromium/components/signin/core/browser/signin_error_controller.h
index 1a2c08a8212..334e426db23 100644
--- a/chromium/components/signin/core/browser/signin_error_controller.h
+++ b/chromium/components/signin/core/browser/signin_error_controller.h
@@ -6,17 +6,22 @@
#define COMPONENTS_SIGNIN_CORE_BROWSER_SIGNIN_ERROR_CONTROLLER_H_
#include <set>
+#include <string>
+
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/observer_list.h"
+#include "base/scoped_observer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "google_apis/gaia/google_service_auth_error.h"
+#include "services/identity/public/cpp/identity_manager.h"
// Keep track of auth errors and expose them to observers in the UI. Services
// that wish to expose auth errors to the user should register an
// AuthStatusProvider to report their current authentication state, and should
// invoke AuthStatusChanged() when their authentication state may have changed.
-class SigninErrorController : public KeyedService {
+class SigninErrorController : public KeyedService,
+ public identity::IdentityManager::Observer {
public:
enum class AccountMode {
// Signin error controller monitors all the accounts. When multiple accounts
@@ -28,19 +33,6 @@ class SigninErrorController : public KeyedService {
PRIMARY_ACCOUNT
};
- class AuthStatusProvider {
- public:
- AuthStatusProvider();
- virtual ~AuthStatusProvider();
-
- // Returns the account id with the status specified by GetAuthStatus().
- virtual std::string GetAccountId() const = 0;
-
- // API invoked by SigninErrorController to get the current auth status of
- // the various signed in services.
- virtual GoogleServiceAuthError GetAuthStatus() const = 0;
- };
-
// The observer class for SigninErrorController lets the controller notify
// observers when an error arises or changes.
class Observer {
@@ -49,26 +41,19 @@ class SigninErrorController : public KeyedService {
virtual void OnErrorChanged() = 0;
};
- explicit SigninErrorController(AccountMode mode);
+ SigninErrorController(AccountMode mode,
+ identity::IdentityManager* identity_manager);
~SigninErrorController() override;
- // Adds a provider which the SigninErrorController object will start querying
- // for auth status.
- void AddProvider(const AuthStatusProvider* provider);
-
- // Removes a provider previously added by SigninErrorController (generally
- // only called in preparation for shutdown).
- void RemoveProvider(const AuthStatusProvider* provider);
-
- // Invoked when the auth status of an AuthStatusProvider has changed.
- void AuthStatusChanged();
+ // KeyedService implementation:
+ void Shutdown() override;
- // True if there exists an error worth elevating to the user.
+ // True if there exists an error worth elevating to the user. Note that
+ // |SigninErrorController| can be running in |AccountMode::ANY_ACCOUNT| mode,
+ // in which case |HasError| can return an error for any account, not just the
+ // Primary Account. See |error_account_id()|.
bool HasError() const;
- // Sets the primary account id. Only used in the PRIMARY_ACCOUNT account mode.
- void SetPrimaryAccountID(const std::string& account_id);
-
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
@@ -76,11 +61,23 @@ class SigninErrorController : public KeyedService {
const GoogleServiceAuthError& auth_error() const { return auth_error_; }
private:
+ // Invoked when the auth status has changed.
+ void Update();
+
+ // identity::IdentityManager::Observer:
+ void OnEndBatchOfRefreshTokenStateChanges() override;
+ void OnErrorStateOfRefreshTokenUpdatedForAccount(
+ const AccountInfo& account_info,
+ const GoogleServiceAuthError& error) override;
+ void OnPrimaryAccountSet(const AccountInfo& primary_account_info) override;
+ void OnPrimaryAccountCleared(
+ const AccountInfo& previous_primary_account_info) override;
+
const AccountMode account_mode_;
- std::set<const AuthStatusProvider*> provider_set_;
+ identity::IdentityManager* identity_manager_;
- // The primary account ID. Only used in the PRIMARY_ACCOUNT account mode.
- std::string primary_account_id_;
+ ScopedObserver<identity::IdentityManager, SigninErrorController>
+ scoped_identity_manager_observer_;
// The account that generated the last auth error.
std::string error_account_id_;
diff --git a/chromium/components/signin/core/browser/signin_error_controller_unittest.cc b/chromium/components/signin/core/browser/signin_error_controller_unittest.cc
index 62bec6a8536..2b88b04cf39 100644
--- a/chromium/components/signin/core/browser/signin_error_controller_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_error_controller_unittest.cc
@@ -9,293 +9,279 @@
#include <functional>
#include <memory>
-#include "base/macros.h"
-#include "components/signin/core/browser/fake_auth_status_provider.h"
+#include "base/scoped_observer.h"
+#include "base/stl_util.h"
+#include "base/test/scoped_task_environment.h"
+#include "services/identity/public/cpp/identity_test_environment.h"
+#include "services/identity/public/cpp/primary_account_mutator.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-static const char kTestAccountId[] = "testuser@test.com";
-static const char kOtherTestAccountId[] = "otheruser@test.com";
+namespace {
-TEST(SigninErrorControllerTest, NoErrorAuthStatusProviders) {
- SigninErrorController error_controller(
- SigninErrorController::AccountMode::ANY_ACCOUNT);
- std::unique_ptr<FakeAuthStatusProvider> provider;
+static const char kTestEmail[] = "me@test.com";
+static const char kOtherTestEmail[] = "you@test.com";
- // No providers.
- ASSERT_FALSE(error_controller.HasError());
+class MockSigninErrorControllerObserver
+ : public SigninErrorController::Observer {
+ public:
+ MOCK_METHOD0(OnErrorChanged, void());
+};
- // Add a provider.
- provider.reset(new FakeAuthStatusProvider(&error_controller));
- ASSERT_FALSE(error_controller.HasError());
+} // namespace
- // Remove the provider.
- provider.reset();
- ASSERT_FALSE(error_controller.HasError());
-}
+TEST(SigninErrorControllerTest, SingleAccount) {
+ MockSigninErrorControllerObserver observer;
+ EXPECT_CALL(observer, OnErrorChanged()).Times(0);
-TEST(SigninErrorControllerTest, ErrorAuthStatusProvider) {
+ base::test::ScopedTaskEnvironment task_environment;
+ identity::IdentityTestEnvironment identity_test_env;
SigninErrorController error_controller(
- SigninErrorController::AccountMode::ANY_ACCOUNT);
- std::unique_ptr<FakeAuthStatusProvider> provider;
- std::unique_ptr<FakeAuthStatusProvider> error_provider;
-
- provider.reset(new FakeAuthStatusProvider(&error_controller));
- ASSERT_FALSE(error_controller.HasError());
-
- error_provider.reset(new FakeAuthStatusProvider(&error_controller));
- error_provider->SetAuthError(
- kTestAccountId,
- GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
- ASSERT_TRUE(error_controller.HasError());
-
- error_provider.reset();
- ASSERT_FALSE(error_controller.HasError());
-
- provider.reset();
- // All providers should be removed now.
+ SigninErrorController::AccountMode::ANY_ACCOUNT,
+ identity_test_env.identity_manager());
+ ScopedObserver<SigninErrorController, SigninErrorController::Observer>
+ scoped_observer(&observer);
+ scoped_observer.Add(&error_controller);
ASSERT_FALSE(error_controller.HasError());
+ ::testing::Mock::VerifyAndClearExpectations(&observer);
+
+ // IdentityTestEnvironment does not call OnEndBatchChanges() as part of
+ // MakeAccountAvailable(), and thus the signin error controller is not
+ // updated.
+ EXPECT_CALL(observer, OnErrorChanged()).Times(0);
+
+ std::string test_account_id =
+ identity_test_env.MakeAccountAvailable(kTestEmail).account_id;
+ ::testing::Mock::VerifyAndClearExpectations(&observer);
+
+ GoogleServiceAuthError error1 =
+ GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
+ EXPECT_CALL(observer, OnErrorChanged()).Times(1);
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ test_account_id, error1);
+ EXPECT_TRUE(error_controller.HasError());
+ EXPECT_EQ(error1, error_controller.auth_error());
+ ::testing::Mock::VerifyAndClearExpectations(&observer);
+
+ GoogleServiceAuthError error2 =
+ GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED);
+ EXPECT_CALL(observer, OnErrorChanged()).Times(1);
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ test_account_id, error2);
+ EXPECT_TRUE(error_controller.HasError());
+ EXPECT_EQ(error2, error_controller.auth_error());
+ ::testing::Mock::VerifyAndClearExpectations(&observer);
+
+ EXPECT_CALL(observer, OnErrorChanged()).Times(1);
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ test_account_id, GoogleServiceAuthError::AuthErrorNone());
+ EXPECT_FALSE(error_controller.HasError());
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ error_controller.auth_error());
+ ::testing::Mock::VerifyAndClearExpectations(&observer);
}
-TEST(SigninErrorControllerTest, AuthStatusProviderErrorTransition) {
- SigninErrorController error_controller(
- SigninErrorController::AccountMode::ANY_ACCOUNT);
- std::unique_ptr<FakeAuthStatusProvider> provider0(
- new FakeAuthStatusProvider(&error_controller));
- std::unique_ptr<FakeAuthStatusProvider> provider1(
- new FakeAuthStatusProvider(&error_controller));
+TEST(SigninErrorControllerTest, AccountTransitionAnyAccount) {
+ base::test::ScopedTaskEnvironment task_environment;
+ identity::IdentityTestEnvironment identity_test_env;
- ASSERT_FALSE(error_controller.HasError());
- provider0->SetAuthError(
- kTestAccountId,
- GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
- ASSERT_TRUE(error_controller.HasError());
- provider1->SetAuthError(
- kTestAccountId,
- GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED));
- ASSERT_TRUE(error_controller.HasError());
-
- // Now resolve the auth errors - the menu item should go away.
- provider0->SetAuthError(kTestAccountId,
- GoogleServiceAuthError::AuthErrorNone());
- ASSERT_TRUE(error_controller.HasError());
- provider1->SetAuthError(kTestAccountId,
- GoogleServiceAuthError::AuthErrorNone());
- ASSERT_FALSE(error_controller.HasError());
-
- provider0.reset();
- provider1.reset();
- ASSERT_FALSE(error_controller.HasError());
-}
-
-TEST(SigninErrorControllerTest, AuthStatusProviderAccountTransitionAnyAccount) {
+ std::string test_account_id =
+ identity_test_env.MakeAccountAvailable(kTestEmail).account_id;
+ std::string other_test_account_id =
+ identity_test_env.MakeAccountAvailable(kOtherTestEmail).account_id;
SigninErrorController error_controller(
- SigninErrorController::AccountMode::ANY_ACCOUNT);
- std::unique_ptr<FakeAuthStatusProvider> provider0(
- new FakeAuthStatusProvider(&error_controller));
- std::unique_ptr<FakeAuthStatusProvider> provider1(
- new FakeAuthStatusProvider(&error_controller));
-
+ SigninErrorController::AccountMode::ANY_ACCOUNT,
+ identity_test_env.identity_manager());
ASSERT_FALSE(error_controller.HasError());
- provider0->SetAuthError(
- kTestAccountId,
- GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
- provider1->SetAuthError(
- kOtherTestAccountId,
- GoogleServiceAuthError(GoogleServiceAuthError::NONE));
- ASSERT_TRUE(error_controller.HasError());
- ASSERT_STREQ(kTestAccountId, error_controller.error_account_id().c_str());
-
- // Swap providers reporting errors.
- provider1->set_error_without_status_change(
- GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
- provider0->set_error_without_status_change(
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ test_account_id,
+ GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ other_test_account_id,
GoogleServiceAuthError(GoogleServiceAuthError::NONE));
- error_controller.AuthStatusChanged();
ASSERT_TRUE(error_controller.HasError());
- ASSERT_STREQ(kOtherTestAccountId,
- error_controller.error_account_id().c_str());
+ ASSERT_EQ(test_account_id, error_controller.error_account_id());
// Now resolve the auth errors - the menu item should go away.
- provider0->set_error_without_status_change(
- GoogleServiceAuthError::AuthErrorNone());
- provider1->set_error_without_status_change(
- GoogleServiceAuthError::AuthErrorNone());
- error_controller.AuthStatusChanged();
- ASSERT_FALSE(error_controller.HasError());
-
- provider0.reset();
- provider1.reset();
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ test_account_id, GoogleServiceAuthError::AuthErrorNone());
ASSERT_FALSE(error_controller.HasError());
}
-TEST(SigninErrorControllerTest,
- AuthStatusProviderAccountTransitionPrimaryAccount) {
+// This test exercises behavior on signin/signout, which is not relevant on
+// ChromeOS.
+#if !defined(OS_CHROMEOS)
+TEST(SigninErrorControllerTest, AccountTransitionPrimaryAccount) {
+ base::test::ScopedTaskEnvironment task_environment;
+ identity::IdentityTestEnvironment identity_test_env;
+ identity::PrimaryAccountMutator* primary_account_mutator =
+ identity_test_env.identity_manager()->GetPrimaryAccountMutator();
+
+ std::string test_account_id =
+ identity_test_env.MakeAccountAvailable(kTestEmail).account_id;
+ std::string other_test_account_id =
+ identity_test_env.MakeAccountAvailable(kOtherTestEmail).account_id;
SigninErrorController error_controller(
- SigninErrorController::AccountMode::PRIMARY_ACCOUNT);
- std::unique_ptr<FakeAuthStatusProvider> provider0(
- new FakeAuthStatusProvider(&error_controller));
- std::unique_ptr<FakeAuthStatusProvider> provider1(
- new FakeAuthStatusProvider(&error_controller));
-
+ SigninErrorController::AccountMode::PRIMARY_ACCOUNT,
+ identity_test_env.identity_manager());
ASSERT_FALSE(error_controller.HasError());
- provider0->SetAuthError(
- kTestAccountId,
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ test_account_id,
GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
- provider1->SetAuthError(kOtherTestAccountId,
- GoogleServiceAuthError(GoogleServiceAuthError::NONE));
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ other_test_account_id,
+ GoogleServiceAuthError(GoogleServiceAuthError::NONE));
ASSERT_FALSE(error_controller.HasError()); // No primary account.
- error_controller.SetPrimaryAccountID(kOtherTestAccountId);
- ASSERT_FALSE(error_controller.HasError()); // Error on secondary.
- error_controller.SetPrimaryAccountID(kTestAccountId);
+
+ // Set the primary account.
+ identity_test_env.SetPrimaryAccount(kOtherTestEmail);
+
+ ASSERT_FALSE(error_controller.HasError()); // Error is on secondary.
+
+ // Change the primary account to the account with an error and check that the
+ // error controller updates its error status accordingly.
+ primary_account_mutator->ClearPrimaryAccount(
+ identity::PrimaryAccountMutator::ClearAccountsAction::kKeepAll,
+ signin_metrics::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST,
+ signin_metrics::SignoutDelete::IGNORE_METRIC);
+ identity_test_env.SetPrimaryAccount(kTestEmail);
ASSERT_TRUE(error_controller.HasError());
- ASSERT_STREQ(kTestAccountId, error_controller.error_account_id().c_str());
+ ASSERT_EQ(test_account_id, error_controller.error_account_id());
- // Change the primary account.
- provider1->SetAuthError(
- kOtherTestAccountId,
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ other_test_account_id,
GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
ASSERT_TRUE(error_controller.HasError());
- ASSERT_STREQ(kTestAccountId, error_controller.error_account_id().c_str());
- error_controller.SetPrimaryAccountID(kOtherTestAccountId);
+ ASSERT_EQ(test_account_id, error_controller.error_account_id());
+
+ // Change the primary account again and check that the error controller
+ // updates its error status accordingly.
+ primary_account_mutator->ClearPrimaryAccount(
+ identity::PrimaryAccountMutator::ClearAccountsAction::kKeepAll,
+ signin_metrics::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST,
+ signin_metrics::SignoutDelete::IGNORE_METRIC);
+ identity_test_env.SetPrimaryAccount(kOtherTestEmail);
ASSERT_TRUE(error_controller.HasError());
- ASSERT_STREQ(kOtherTestAccountId,
- error_controller.error_account_id().c_str());
-
- // Signout.
- error_controller.SetPrimaryAccountID("");
+ ASSERT_EQ(other_test_account_id, error_controller.error_account_id());
+
+ // Sign out and check that that the error controller updates its error status
+ // accordingly.
+ primary_account_mutator->ClearPrimaryAccount(
+ identity::PrimaryAccountMutator::ClearAccountsAction::kKeepAll,
+ signin_metrics::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST,
+ signin_metrics::SignoutDelete::IGNORE_METRIC);
ASSERT_FALSE(error_controller.HasError());
-
- provider0.reset();
- provider1.reset();
}
+#endif
// Verify that SigninErrorController handles errors properly.
TEST(SigninErrorControllerTest, AuthStatusEnumerateAllErrors) {
+ base::test::ScopedTaskEnvironment task_environment;
+ identity::IdentityTestEnvironment identity_test_env;
+
+ std::string test_account_id =
+ identity_test_env.MakeAccountAvailable(kTestEmail).account_id;
SigninErrorController error_controller(
- SigninErrorController::AccountMode::ANY_ACCOUNT);
- typedef struct {
- GoogleServiceAuthError::State error_state;
- bool is_error;
- } ErrorTableEntry;
-
- ErrorTableEntry table[] = {
- { GoogleServiceAuthError::NONE, false },
- { GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, true },
- { GoogleServiceAuthError::USER_NOT_SIGNED_UP, true },
- { GoogleServiceAuthError::CONNECTION_FAILED, false },
- { GoogleServiceAuthError::CAPTCHA_REQUIRED, true },
- { GoogleServiceAuthError::ACCOUNT_DELETED, true },
- { GoogleServiceAuthError::ACCOUNT_DISABLED, true },
- { GoogleServiceAuthError::SERVICE_UNAVAILABLE, false },
- { GoogleServiceAuthError::TWO_FACTOR, true },
- { GoogleServiceAuthError::REQUEST_CANCELED, false },
- { GoogleServiceAuthError::HOSTED_NOT_ALLOWED_DEPRECATED, false },
- { GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE, true },
- { GoogleServiceAuthError::SERVICE_ERROR, true },
- { GoogleServiceAuthError::WEB_LOGIN_REQUIRED, true },
- };
- static_assert(arraysize(table) == GoogleServiceAuthError::NUM_STATES,
- "table array does not match the number of auth error types");
-
- for (size_t i = 0; i < arraysize(table); ++i) {
- if (GoogleServiceAuthError::IsDeprecated(table[i].error_state))
+ SigninErrorController::AccountMode::ANY_ACCOUNT,
+ identity_test_env.identity_manager());
+
+ GoogleServiceAuthError::State table[] = {
+ GoogleServiceAuthError::NONE,
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS,
+ GoogleServiceAuthError::USER_NOT_SIGNED_UP,
+ GoogleServiceAuthError::CONNECTION_FAILED,
+ GoogleServiceAuthError::CAPTCHA_REQUIRED,
+ GoogleServiceAuthError::ACCOUNT_DELETED,
+ GoogleServiceAuthError::ACCOUNT_DISABLED,
+ GoogleServiceAuthError::SERVICE_UNAVAILABLE,
+ GoogleServiceAuthError::TWO_FACTOR,
+ GoogleServiceAuthError::REQUEST_CANCELED,
+ GoogleServiceAuthError::HOSTED_NOT_ALLOWED_DEPRECATED,
+ GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE,
+ GoogleServiceAuthError::SERVICE_ERROR,
+ GoogleServiceAuthError::WEB_LOGIN_REQUIRED};
+ static_assert(base::size(table) == GoogleServiceAuthError::NUM_STATES,
+ "table array does not match the number of auth error types");
+
+ for (GoogleServiceAuthError::State state : table) {
+ if (GoogleServiceAuthError::IsDeprecated(state))
continue;
- FakeAuthStatusProvider provider(&error_controller);
- provider.SetAuthError(kTestAccountId,
- GoogleServiceAuthError(table[i].error_state));
- EXPECT_EQ(error_controller.HasError(), table[i].is_error);
+ GoogleServiceAuthError error(state);
+
+ if (error.IsTransientError())
+ continue; // Only persistent errors or non-errors are reported.
+
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ test_account_id, error);
- if (table[i].is_error) {
- EXPECT_EQ(table[i].error_state, error_controller.auth_error().state());
- EXPECT_STREQ(kTestAccountId, error_controller.error_account_id().c_str());
+ EXPECT_EQ(error_controller.HasError(), error.IsPersistentError());
+
+ if (error.IsPersistentError()) {
+ EXPECT_EQ(state, error_controller.auth_error().state());
+ EXPECT_EQ(test_account_id, error_controller.error_account_id());
} else {
EXPECT_EQ(GoogleServiceAuthError::NONE,
error_controller.auth_error().state());
- EXPECT_STREQ("", error_controller.error_account_id().c_str());
+ EXPECT_EQ("", error_controller.error_account_id());
}
}
}
// Verify that existing error is not replaced by new error.
TEST(SigninErrorControllerTest, AuthStatusChange) {
+ base::test::ScopedTaskEnvironment task_environment;
+ identity::IdentityTestEnvironment identity_test_env;
+
+ std::string test_account_id =
+ identity_test_env.MakeAccountAvailable(kTestEmail).account_id;
+ std::string other_test_account_id =
+ identity_test_env.MakeAccountAvailable(kOtherTestEmail).account_id;
SigninErrorController error_controller(
- SigninErrorController::AccountMode::ANY_ACCOUNT);
- std::unique_ptr<FakeAuthStatusProvider> fake_provider0(
- new FakeAuthStatusProvider(&error_controller));
- std::unique_ptr<FakeAuthStatusProvider> fake_provider1(
- new FakeAuthStatusProvider(&error_controller));
-
- // If there are multiple providers in the provider set...
- //
- // | provider0 | provider1 | ...
- // | NONE | INVALID_GAIA_CREDENTIALS | ...
- //
- // SigninErrorController picks the first error found when iterating through
- // the set. But if another error crops up...
- //
- // | provider0 | provider1 | ...
- // | SERVICE_ERROR | INVALID_GAIA_CREDENTIALS | ...
- //
- // we want the controller to still use the original error.
-
- // The provider pointers are stored in a set, which is sorted by std::less.
- std::less<SigninErrorController::AuthStatusProvider*> compare;
- FakeAuthStatusProvider* provider0 =
- compare(fake_provider0.get(), fake_provider1.get()) ?
- fake_provider0.get() : fake_provider1.get();
- FakeAuthStatusProvider* provider1 =
- provider0 == fake_provider0.get() ?
- fake_provider1.get() : fake_provider0.get();
-
- provider0->SetAuthError(
- kTestAccountId,
- GoogleServiceAuthError(
- GoogleServiceAuthError::NONE));
- provider1->SetAuthError(
- kOtherTestAccountId,
- GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+ SigninErrorController::AccountMode::ANY_ACCOUNT,
+ identity_test_env.identity_manager());
+ ASSERT_FALSE(error_controller.HasError());
+
+ // Set an error for other_test_account_id.
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ test_account_id, GoogleServiceAuthError(GoogleServiceAuthError::NONE));
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ other_test_account_id,
+ GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
ASSERT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS,
error_controller.auth_error().state());
- ASSERT_STREQ(kOtherTestAccountId,
- error_controller.error_account_id().c_str());
+ ASSERT_EQ(other_test_account_id, error_controller.error_account_id());
- // Change the 1st provider's error.
- provider1->SetAuthError(
- kOtherTestAccountId,
+ // Change the error for other_test_account_id.
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ other_test_account_id,
GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_ERROR));
ASSERT_EQ(GoogleServiceAuthError::SERVICE_ERROR,
error_controller.auth_error().state());
- ASSERT_STREQ(kOtherTestAccountId,
- error_controller.error_account_id().c_str());
+ ASSERT_EQ(other_test_account_id, error_controller.error_account_id());
- // Set the 0th provider's error -- nothing should change.
- provider0->SetAuthError(
- kTestAccountId,
+ // Set the error for test_account_id -- nothing should change.
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ test_account_id,
GoogleServiceAuthError(
GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE));
ASSERT_EQ(GoogleServiceAuthError::SERVICE_ERROR,
error_controller.auth_error().state());
- ASSERT_STREQ(kOtherTestAccountId,
- error_controller.error_account_id().c_str());
+ ASSERT_EQ(other_test_account_id, error_controller.error_account_id());
- // Clear the 1st provider's error, so the 0th provider's error is used.
- provider1->SetAuthError(
- kOtherTestAccountId,
- GoogleServiceAuthError(
- GoogleServiceAuthError::NONE));
+ // Clear the error for other_test_account_id, so the test_account_id's error
+ // is used.
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ other_test_account_id,
+ GoogleServiceAuthError(GoogleServiceAuthError::NONE));
ASSERT_EQ(GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE,
error_controller.auth_error().state());
- ASSERT_STREQ(kTestAccountId, error_controller.error_account_id().c_str());
+ ASSERT_EQ(test_account_id, error_controller.error_account_id());
- fake_provider0.reset();
- fake_provider1.reset();
+ // Clear the remaining error.
+ identity_test_env.UpdatePersistentErrorOfRefreshTokenForAccount(
+ test_account_id, GoogleServiceAuthError(GoogleServiceAuthError::NONE));
ASSERT_FALSE(error_controller.HasError());
}
diff --git a/chromium/components/signin/core/browser/signin_header_helper_unittest.cc b/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
index 5414b2f896f..1697fd9bcd2 100644
--- a/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
@@ -8,8 +8,8 @@
#include <string>
#include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
+#include "base/test/scoped_task_environment.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/prefs/pref_member.h"
#include "components/signin/core/browser/account_consistency_method.h"
@@ -112,7 +112,7 @@ class SigninHeaderHelperTest : public testing::Test {
}
#endif
- base::MessageLoop loop_;
+ base::test::ScopedTaskEnvironment task_environment_;
bool sync_enabled_ = false;
bool sync_has_auth_error_ = false;
@@ -327,37 +327,6 @@ TEST_F(SigninHeaderHelperTest, TestDiceMigration) {
kDiceProtocolVersion, client_id.c_str()));
}
-// Tests that a Dice request is returned only when there is an authentication
-// error if the method is kDiceFixAuthErrors.
-TEST_F(SigninHeaderHelperTest, TestDiceFixAuthError) {
- account_consistency_ = AccountConsistencyMethod::kDiceFixAuthErrors;
- // No Dice request unless all conditions are met.
- CheckDiceHeaderRequest(GURL("https://accounts.google.com"), "0123456789",
- "mode=0,enable_account_consistency=false", "");
- sync_has_auth_error_ = false;
- sync_enabled_ = true;
- CheckDiceHeaderRequest(GURL("https://accounts.google.com"), "0123456789",
- "mode=0,enable_account_consistency=false", "");
- sync_has_auth_error_ = true;
- sync_enabled_ = false;
- CheckDiceHeaderRequest(GURL("https://accounts.google.com"), "0123456789",
- "mode=0,enable_account_consistency=false", "");
- sync_has_auth_error_ = true;
- sync_enabled_ = true;
- CheckDiceHeaderRequest(GURL("https://accounts.google.com"), "", "", "");
-
- // Dice request when there is an account id, Sync is enabled and in error
- // state.
- std::string client_id = GaiaUrls::GetInstance()->oauth2_chrome_client_id();
- CheckDiceHeaderRequest(
- GURL("https://accounts.google.com"), "0123456789",
- "mode=0,enable_account_consistency=false",
- base::StringPrintf("version=%s,client_id=%s,device_id=DeviceID,"
- "sync_account_id=0123456789,signin_mode=sync_account,"
- "signout_mode=no_confirmation",
- kDiceProtocolVersion, client_id.c_str()));
-}
-
// Tests that the Mirror request is returned with the GAIA Id on Drive origin,
// even if account consistency is disabled.
TEST_F(SigninHeaderHelperTest, TestMirrorRequestDrive) {
diff --git a/chromium/components/signin/core/browser/signin_internals_util.cc b/chromium/components/signin/core/browser/signin_internals_util.cc
index fa9d492224e..68884202990 100644
--- a/chromium/components/signin/core/browser/signin_internals_util.cc
+++ b/chromium/components/signin/core/browser/signin_internals_util.cc
@@ -37,8 +37,6 @@ std::string SigninStatusFieldToString(TimedSigninStatusField field) {
switch (field) {
ENUM_CASE(AUTHENTICATION_RESULT_RECEIVED);
ENUM_CASE(REFRESH_TOKEN_RECEIVED);
- ENUM_CASE(SIGNIN_STARTED);
- ENUM_CASE(SIGNIN_COMPLETED);
case TIMED_FIELDS_END:
NOTREACHED();
return std::string();
diff --git a/chromium/components/signin/core/browser/signin_internals_util.h b/chromium/components/signin/core/browser/signin_internals_util.h
index d397d04a712..576710b70c2 100644
--- a/chromium/components/signin/core/browser/signin_internals_util.h
+++ b/chromium/components/signin/core/browser/signin_internals_util.h
@@ -45,8 +45,6 @@ enum TimedSigninStatusField {
TIMED_FIELDS_BEGIN = TIMED_FIELDS_BEGIN_UNTYPED,
AUTHENTICATION_RESULT_RECEIVED = TIMED_FIELDS_BEGIN,
REFRESH_TOKEN_RECEIVED,
- SIGNIN_STARTED,
- SIGNIN_COMPLETED,
TIMED_FIELDS_END
};
@@ -65,14 +63,6 @@ std::string TokenPrefPath(const std::string& service_name);
std::string SigninStatusFieldToString(UntimedSigninStatusField field);
std::string SigninStatusFieldToString(TimedSigninStatusField field);
-// An Observer class for authentication and token diagnostic information.
-class SigninDiagnosticsObserver {
- public:
- // Credentials and signin related changes.
- virtual void NotifySigninValueChanged(const TimedSigninStatusField& field,
- const std::string& value) {}
-};
-
// Gets the first 6 hex characters of the SHA256 hash of the passed in string.
// These are enough to perform equality checks across a single users tokens,
// while preventing outsiders from reverse-engineering the actual token from
diff --git a/chromium/components/signin/core/browser/signin_investigator_unittest.cc b/chromium/components/signin/core/browser/signin_investigator_unittest.cc
index cba6e2028c9..cb861a03128 100644
--- a/chromium/components/signin/core/browser/signin_investigator_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_investigator_unittest.cc
@@ -5,12 +5,13 @@
#include <string>
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_task_environment.h"
#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
#include "components/signin/core/browser/signin_investigator.h"
-#include "components/signin/core/browser/signin_manager_base.h"
#include "components/signin/core/browser/signin_metrics.h"
#include "components/signin/core/browser/signin_pref_names.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "services/identity/public/cpp/identity_test_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
using signin_metrics::AccountEquality;
@@ -24,13 +25,17 @@ const char kEmptyId[] = "";
class FakeProvider : public SigninInvestigator::DependencyProvider {
public:
- FakeProvider(const std::string& last_email, const std::string& last_id) {
- SigninManagerBase::RegisterProfilePrefs(prefs_.registry());
+ FakeProvider(const std::string& last_email, const std::string& last_id)
+ : identity_test_env_(/*test_url_loader_factory=*/nullptr, &prefs_) {
prefs_.SetString(prefs::kGoogleServicesLastUsername, last_email);
prefs_.SetString(prefs::kGoogleServicesLastAccountId, last_id);
}
PrefService* GetPrefs() override { return &prefs_; }
- TestingPrefServiceSimple prefs_;
+
+ private:
+ base::test::ScopedTaskEnvironment task_environment_;
+ sync_preferences::TestingPrefServiceSyncable prefs_;
+ identity::IdentityTestEnvironment identity_test_env_;
};
} // namespace
diff --git a/chromium/components/signin/core/browser/signin_manager.cc b/chromium/components/signin/core/browser/signin_manager.cc
index f3c819f1a3f..5ac21878b9b 100644
--- a/chromium/components/signin/core/browser/signin_manager.cc
+++ b/chromium/components/signin/core/browser/signin_manager.cc
@@ -30,14 +30,9 @@ SigninManager::SigninManager(
ProfileOAuth2TokenService* token_service,
AccountTrackerService* account_tracker_service,
GaiaCookieManagerService* cookie_manager_service,
- SigninErrorController* signin_error_controller,
signin::AccountConsistencyMethod account_consistency)
- : SigninManagerBase(client,
- account_tracker_service,
- signin_error_controller),
+ : SigninManagerBase(client, token_service, account_tracker_service),
type_(SIGNIN_TYPE_NONE),
- client_(client),
- token_service_(token_service),
cookie_manager_service_(cookie_manager_service),
account_consistency_(account_consistency),
signin_manager_signed_in_(false),
@@ -90,8 +85,6 @@ bool SigninManager::PrepareForSignin(SigninType type,
password_.assign(password);
signin_manager_signed_in_ = false;
user_info_fetched_by_account_tracker_ = false;
- NotifyDiagnosticsObservers(signin_internals_util::SIGNIN_STARTED,
- SigninTypeToString(type));
return true;
}
@@ -128,7 +121,7 @@ void SigninManager::CopyCredentialsFrom(const SigninManager& source) {
possibly_invalid_email_ = source.possibly_invalid_email_;
temp_refresh_token_ = source.temp_refresh_token_;
password_ = source.password_;
- source.client_->AfterCredentialsCopied();
+ source.signin_client()->AfterCredentialsCopied();
}
void SigninManager::ClearTransientSigninData() {
@@ -177,7 +170,7 @@ void SigninManager::StartSignOut(
signin_metrics::ProfileSignout signout_source_metric,
signin_metrics::SignoutDelete signout_delete_metric,
RemoveAccountsOption remove_option) {
- client_->PreSignOut(
+ signin_client()->PreSignOut(
base::BindOnce(&SigninManager::OnSignoutDecisionReached,
base::Unretained(this), signout_source_metric,
signout_delete_metric, remove_option),
@@ -221,13 +214,13 @@ void SigninManager::OnSignoutDecisionReached(
const std::string account_id = GetAuthenticatedAccountId();
const std::string username = account_info.email;
const base::Time signin_time =
- base::Time::FromInternalValue(
- client_->GetPrefs()->GetInt64(prefs::kSignedInTime));
+ base::Time::FromDeltaSinceWindowsEpoch(base::TimeDelta::FromMicroseconds(
+ signin_client()->GetPrefs()->GetInt64(prefs::kSignedInTime)));
ClearAuthenticatedAccountId();
- client_->GetPrefs()->ClearPref(prefs::kGoogleServicesHostedDomain);
- client_->GetPrefs()->ClearPref(prefs::kGoogleServicesAccountId);
- client_->GetPrefs()->ClearPref(prefs::kGoogleServicesUserAccountId);
- client_->GetPrefs()->ClearPref(prefs::kSignedInTime);
+ signin_client()->GetPrefs()->ClearPref(prefs::kGoogleServicesHostedDomain);
+ signin_client()->GetPrefs()->ClearPref(prefs::kGoogleServicesAccountId);
+ signin_client()->GetPrefs()->ClearPref(prefs::kGoogleServicesUserAccountId);
+ signin_client()->GetPrefs()->ClearPref(prefs::kSignedInTime);
// Determine the duration the user was logged in and log that to UMA.
if (!signin_time.is_null()) {
@@ -243,13 +236,13 @@ void SigninManager::OnSignoutDecisionReached(
case RemoveAccountsOption::kRemoveAllAccounts:
VLOG(0) << "Revoking all refresh tokens on server. Reason: sign out, "
<< "IsSigninAllowed: " << IsSigninAllowed();
- token_service_->RevokeAllCredentials(
+ token_service()->RevokeAllCredentials(
signin_metrics::SourceForRefreshTokenOperation::
kSigninManager_ClearPrimaryAccount);
break;
case RemoveAccountsOption::kRemoveAuthenticatedAccountIfInError:
- if (token_service_->RefreshTokenHasError(account_id))
- token_service_->RevokeCredentials(
+ if (token_service()->RefreshTokenHasError(account_id))
+ token_service()->RevokeCredentials(
account_id, signin_metrics::SourceForRefreshTokenOperation::
kSigninManager_ClearPrimaryAccount);
break;
@@ -261,9 +254,8 @@ void SigninManager::OnSignoutDecisionReached(
FireGoogleSignedOut(account_info);
}
-void SigninManager::Initialize(PrefService* local_state) {
- SigninManagerBase::Initialize(local_state);
-
+void SigninManager::FinalizeInitBeforeLoadingRefreshTokens(
+ PrefService* local_state) {
// local_state can be null during unit tests.
if (local_state) {
local_state_pref_registrar_.Init(local_state);
@@ -272,13 +264,12 @@ void SigninManager::Initialize(PrefService* local_state) {
base::Bind(&SigninManager::OnGoogleServicesUsernamePatternChanged,
weak_pointer_factory_.GetWeakPtr()));
}
- signin_allowed_.Init(prefs::kSigninAllowed,
- client_->GetPrefs(),
+ signin_allowed_.Init(prefs::kSigninAllowed, signin_client()->GetPrefs(),
base::Bind(&SigninManager::OnSigninAllowedPrefChanged,
base::Unretained(this)));
std::string account_id =
- client_->GetPrefs()->GetString(prefs::kGoogleServicesAccountId);
+ signin_client()->GetPrefs()->GetString(prefs::kGoogleServicesAccountId);
std::string user = account_id.empty() ? std::string() :
account_tracker_service()->GetAccountInfo(account_id).email;
if (!account_id.empty() && (!IsAllowedUsername(user) || !IsSigninAllowed())) {
@@ -307,12 +298,11 @@ void SigninManager::Initialize(PrefService* local_state) {
// It is important to only load credentials after starting to observe the
// token service.
- token_service_->AddObserver(this);
- token_service_->LoadCredentials(GetAuthenticatedAccountId());
+ token_service()->AddObserver(this);
}
void SigninManager::Shutdown() {
- token_service_->RemoveObserver(this);
+ token_service()->RemoveObserver(this);
account_tracker_service()->RemoveObserver(this);
local_state_pref_registrar_.RemoveAll();
SigninManagerBase::Shutdown();
@@ -386,8 +376,6 @@ void SigninManager::MergeSigninCredentialIntoCookieJar() {
}
void SigninManager::CompletePendingSignin() {
- NotifyDiagnosticsObservers(signin_internals_util::SIGNIN_COMPLETED,
- "Successful");
DCHECK(!possibly_invalid_account_id_.empty());
OnSignedIn();
@@ -395,7 +383,7 @@ void SigninManager::CompletePendingSignin() {
if (!temp_refresh_token_.empty()) {
std::string account_id = GetAuthenticatedAccountId();
- token_service_->UpdateCredentials(
+ token_service()->UpdateCredentials(
account_id, temp_refresh_token_,
signin_metrics::SourceForRefreshTokenOperation::
kSigninManager_LegacyPreDiceSigninFlow);
@@ -418,8 +406,9 @@ void SigninManager::OnExternalSigninCompleted(const std::string& username) {
void SigninManager::OnSignedIn() {
bool reauth_in_progress = IsAuthenticated();
- client_->GetPrefs()->SetInt64(prefs::kSignedInTime,
- base::Time::Now().ToInternalValue());
+ signin_client()->GetPrefs()->SetInt64(
+ prefs::kSignedInTime,
+ base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
SetAuthenticatedAccountInfo(possibly_invalid_gaia_id_,
possibly_invalid_email_);
@@ -433,8 +422,8 @@ void SigninManager::OnSignedIn() {
if (!reauth_in_progress)
FireGoogleSigninSucceeded();
- signin_metrics::LogSigninProfile(client_->IsFirstRun(),
- client_->GetInstallDate());
+ signin_metrics::LogSigninProfile(signin_client()->IsFirstRun(),
+ signin_client()->GetInstallDate());
PostSignedIn();
}
@@ -457,8 +446,8 @@ void SigninManager::PostSignedIn() {
if (!signin_manager_signed_in_ || !user_info_fetched_by_account_tracker_)
return;
- client_->PostSignedIn(GetAuthenticatedAccountId(),
- GetAuthenticatedAccountInfo().email, password_);
+ signin_client()->PostSignedIn(GetAuthenticatedAccountId(),
+ GetAuthenticatedAccountInfo().email, password_);
password_.clear();
}
@@ -476,7 +465,7 @@ void SigninManager::OnAccountUpdateFailed(const std::string& account_id) {
}
void SigninManager::OnRefreshTokensLoaded() {
- token_service_->RemoveObserver(this);
+ token_service()->RemoveObserver(this);
if (account_tracker_service()->GetMigrationState() ==
AccountTrackerService::MIGRATION_IN_PROGRESS) {
@@ -484,12 +473,12 @@ void SigninManager::OnRefreshTokensLoaded() {
}
// Remove account information from the account tracker service if needed.
- if (token_service_->HasLoadCredentialsFinishedWithNoErrors()) {
+ if (token_service()->HasLoadCredentialsFinishedWithNoErrors()) {
std::vector<AccountInfo> accounts_in_tracker_service =
account_tracker_service()->GetAccounts();
for (const auto& account : accounts_in_tracker_service) {
if (GetAuthenticatedAccountId() != account.account_id &&
- !token_service_->RefreshTokenIsAvailable(account.account_id)) {
+ !token_service()->RefreshTokenIsAvailable(account.account_id)) {
DVLOG(0) << "Removed account from account tracker service: "
<< account.account_id;
account_tracker_service()->RemoveAccount(account.account_id);
diff --git a/chromium/components/signin/core/browser/signin_manager.h b/chromium/components/signin/core/browser/signin_manager.h
index 83682f78a60..cf3bbc158b3 100644
--- a/chromium/components/signin/core/browser/signin_manager.h
+++ b/chromium/components/signin/core/browser/signin_manager.h
@@ -48,9 +48,6 @@
class GaiaCookieManagerService;
class GoogleServiceAuthError;
class PrefService;
-class ProfileOAuth2TokenService;
-class SigninClient;
-class SigninErrorController;
namespace identity {
class IdentityManager;
@@ -88,7 +85,6 @@ class SigninManager : public SigninManagerBase,
ProfileOAuth2TokenService* token_service,
AccountTrackerService* account_tracker_service,
GaiaCookieManagerService* cookie_manager_service,
- SigninErrorController* signin_error_controller,
signin::AccountConsistencyMethod account_consistency);
~SigninManager() override;
@@ -143,7 +139,9 @@ class SigninManager : public SigninManagerBase,
// On platforms where SigninManager is responsible for dealing with
// invalid username policy updates, we need to check this during
// initialization and sign the user out.
- void Initialize(PrefService* local_state) override;
+ void FinalizeInitBeforeLoadingRefreshTokens(
+ PrefService* local_state) override;
+
void Shutdown() override;
// If applicable, merge the signed in account into the cookie jar.
@@ -268,14 +266,6 @@ class SigninManager : public SigninManagerBase,
// token service so that it does not need to mint new ones.
std::string temp_refresh_token_;
- // The SigninClient object associated with this object. Must outlive this
- // object.
- SigninClient* client_;
-
- // The ProfileOAuth2TokenService instance associated with this object. Must
- // outlive this object.
- ProfileOAuth2TokenService* token_service_;
-
// Object used to use the token to push a GAIA cookie into the cookie jar.
GaiaCookieManagerService* cookie_manager_service_;
diff --git a/chromium/components/signin/core/browser/signin_manager_base.cc b/chromium/components/signin/core/browser/signin_manager_base.cc
index a75a5a1d872..6012474fe02 100644
--- a/chromium/components/signin/core/browser/signin_manager_base.cc
+++ b/chromium/components/signin/core/browser/signin_manager_base.cc
@@ -16,8 +16,8 @@
#include "components/prefs/pref_service.h"
#include "components/signin/core/browser/account_info.h"
#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_client.h"
-#include "components/signin/core/browser/signin_error_controller.h"
#include "components/signin/core/browser/signin_pref_names.h"
#include "components/signin/core/browser/signin_switches.h"
#include "google_apis/gaia/gaia_auth_util.h"
@@ -26,11 +26,11 @@
SigninManagerBase::SigninManagerBase(
SigninClient* client,
- AccountTrackerService* account_tracker_service,
- SigninErrorController* signin_error_controller)
+ ProfileOAuth2TokenService* token_service,
+ AccountTrackerService* account_tracker_service)
: client_(client),
+ token_service_(token_service),
account_tracker_service_(account_tracker_service),
- signin_error_controller_(signin_error_controller),
initialized_(false),
weak_pointer_factory_(this) {
DCHECK(client_);
@@ -56,6 +56,7 @@ void SigninManagerBase::RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(prefs::kSigninAllowed, true);
registry->RegisterInt64Pref(prefs::kSignedInTime,
base::Time().ToInternalValue());
+ registry->RegisterBooleanPref(prefs::kSignedInWithCredentialProvider, false);
// Deprecated prefs: will be removed in a future release.
registry->RegisterStringPref(prefs::kGoogleServicesUsername, std::string());
@@ -147,8 +148,13 @@ void SigninManagerBase::Initialize(PrefService* local_state) {
}
SetAuthenticatedAccountId(account_id);
}
+ FinalizeInitBeforeLoadingRefreshTokens(local_state);
+ token_service()->LoadCredentials(GetAuthenticatedAccountId());
}
+void SigninManagerBase::FinalizeInitBeforeLoadingRefreshTokens(
+ PrefService* local_state) {}
+
bool SigninManagerBase::IsInitialized() const { return initialized_; }
bool SigninManagerBase::IsSigninAllowed() const {
@@ -214,15 +220,10 @@ void SigninManagerBase::SetAuthenticatedAccountId(
// Commit authenticated account info immediately so that it does not get lost
// if Chrome crashes before the next commit interval.
client_->GetPrefs()->CommitPendingWrite();
-
- if (signin_error_controller_)
- signin_error_controller_->SetPrimaryAccountID(authenticated_account_id_);
}
void SigninManagerBase::ClearAuthenticatedAccountId() {
authenticated_account_id_.clear();
- if (signin_error_controller_)
- signin_error_controller_->SetPrimaryAccountID(std::string());
}
bool SigninManagerBase::IsAuthenticated() const {
@@ -245,20 +246,3 @@ void SigninManagerBase::AddObserver(Observer* observer) {
void SigninManagerBase::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
-
-void SigninManagerBase::AddSigninDiagnosticsObserver(
- signin_internals_util::SigninDiagnosticsObserver* observer) {
- signin_diagnostics_observers_.AddObserver(observer);
-}
-
-void SigninManagerBase::RemoveSigninDiagnosticsObserver(
- signin_internals_util::SigninDiagnosticsObserver* observer) {
- signin_diagnostics_observers_.RemoveObserver(observer);
-}
-
-void SigninManagerBase::NotifyDiagnosticsObservers(
- const signin_internals_util::TimedSigninStatusField& field,
- const std::string& value) {
- for (auto& observer : signin_diagnostics_observers_)
- observer.NotifySigninValueChanged(field, value);
-}
diff --git a/chromium/components/signin/core/browser/signin_manager_base.h b/chromium/components/signin/core/browser/signin_manager_base.h
index e30a2ea1451..f75a647f315 100644
--- a/chromium/components/signin/core/browser/signin_manager_base.h
+++ b/chromium/components/signin/core/browser/signin_manager_base.h
@@ -41,8 +41,8 @@
class AccountTrackerService;
class PrefRegistrySimple;
class PrefService;
+class ProfileOAuth2TokenService;
class SigninClient;
-class SigninErrorController;
class SigninManagerBase : public KeyedService {
public:
@@ -95,8 +95,8 @@ class SigninManagerBase : public KeyedService {
private:
#endif
SigninManagerBase(SigninClient* client,
- AccountTrackerService* account_tracker_service,
- SigninErrorController* signin_error_controller);
+ ProfileOAuth2TokenService* token_service,
+ AccountTrackerService* account_tracker_service);
#if !defined(OS_CHROMEOS)
public:
#endif
@@ -110,7 +110,7 @@ class SigninManagerBase : public KeyedService {
static void RegisterPrefs(PrefRegistrySimple* registry);
// If user was signed in, load tokens from DB if available.
- virtual void Initialize(PrefService* local_state);
+ void Initialize(PrefService* local_state);
bool IsInitialized() const;
// Returns true if a signin to Chrome is allowed (by policy or pref).
@@ -154,15 +154,11 @@ class SigninManagerBase : public KeyedService {
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
- // Methods to register or remove SigninDiagnosticObservers.
- void AddSigninDiagnosticsObserver(
- signin_internals_util::SigninDiagnosticsObserver* observer);
- void RemoveSigninDiagnosticsObserver(
- signin_internals_util::SigninDiagnosticsObserver* observer);
-
// Gives access to the SigninClient instance associated with this instance.
SigninClient* signin_client() const { return client_; }
+ ProfileOAuth2TokenService* token_service() const { return token_service_; }
+
// Adds a callback that will be called when this instance is shut down.Not
// intended for general usage, but rather for usage only by the Identity
// Service implementation during the time period of conversion of Chrome to
@@ -177,6 +173,10 @@ class SigninManagerBase : public KeyedService {
return account_tracker_service_;
}
+ // Invoked at the end of |Initialize| before the refresh token for the primary
+ // account is loaded.
+ virtual void FinalizeInitBeforeLoadingRefreshTokens(PrefService* local_state);
+
// Sets the authenticated user's account id.
// If the user is already authenticated with the same account id, then this
// method is a no-op.
@@ -196,11 +196,6 @@ class SigninManagerBase : public KeyedService {
// Makes sure list is empty on destruction.
base::ObserverList<Observer, true>::Unchecked observer_list_;
- // Helper method to notify all registered diagnostics observers with.
- void NotifyDiagnosticsObservers(
- const signin_internals_util::TimedSigninStatusField& field,
- const std::string& value);
-
private:
friend class FakeSigninManagerBase;
friend class FakeSigninManager;
@@ -211,17 +206,17 @@ class SigninManagerBase : public KeyedService {
friend class SigninManager;
SigninClient* client_;
+
+ // The ProfileOAuth2TokenService instance associated with this object. Must
+ // outlive this object.
+ ProfileOAuth2TokenService* token_service_;
+
AccountTrackerService* account_tracker_service_;
- SigninErrorController* signin_error_controller_;
bool initialized_;
// Account id after successful authentication.
std::string authenticated_account_id_;
- // The list of SigninDiagnosticObservers.
- base::ObserverList<signin_internals_util::SigninDiagnosticsObserver,
- true>::Unchecked signin_diagnostics_observers_;
-
// The list of callbacks notified on shutdown.
base::CallbackList<void()> on_shutdown_callback_list_;
diff --git a/chromium/components/signin/core/browser/signin_manager_unittest.cc b/chromium/components/signin/core/browser/signin_manager_unittest.cc
index 75bd3d8c506..5cb99d8efd2 100644
--- a/chromium/components/signin/core/browser/signin_manager_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_manager_unittest.cc
@@ -11,8 +11,8 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
@@ -77,8 +77,7 @@ class SigninManagerTest : public testing::Test {
SigninManagerTest()
: test_signin_client_(&user_prefs_),
token_service_(&user_prefs_),
- cookie_manager_service_(&token_service_,
- &test_signin_client_),
+ cookie_manager_service_(&token_service_, &test_signin_client_),
account_consistency_(signin::AccountConsistencyMethod::kDisabled) {
AccountFetcherService::RegisterPrefs(user_prefs_.registry());
AccountTrackerService::RegisterPrefs(user_prefs_.registry());
@@ -123,8 +122,7 @@ class SigninManagerTest : public testing::Test {
DCHECK(!manager_);
manager_ = std::make_unique<SigninManager>(
&test_signin_client_, &token_service_, &account_tracker_,
- &cookie_manager_service_, nullptr /* signin_error_controller */,
- account_consistency_);
+ &cookie_manager_service_, account_consistency_);
manager_->Initialize(&local_state_);
manager_->AddObserver(&test_observer_);
}
@@ -156,13 +154,13 @@ class SigninManagerTest : public testing::Test {
manager_->CompletePendingSignin();
}
- base::MessageLoop loop_;
+ base::test::ScopedTaskEnvironment task_environment_;
sync_preferences::TestingPrefServiceSyncable user_prefs_;
TestingPrefServiceSimple local_state_;
TestSigninClient test_signin_client_;
FakeProfileOAuth2TokenService token_service_;
AccountTrackerService account_tracker_;
- FakeGaiaCookieManagerService cookie_manager_service_;
+ GaiaCookieManagerService cookie_manager_service_;
FakeAccountFetcherService account_fetcher_;
std::unique_ptr<SigninManager> manager_;
TestSigninManagerObserver test_observer_;
@@ -499,8 +497,7 @@ TEST_F(SigninManagerTest, GaiaIdMigration) {
PrefService* client_prefs = signin_client()->GetPrefs();
client_prefs->SetInteger(prefs::kAccountIdMigrationState,
AccountTrackerService::MIGRATION_NOT_STARTED);
- ListPrefUpdate update(client_prefs,
- AccountTrackerService::kAccountInfoPref);
+ ListPrefUpdate update(client_prefs, prefs::kAccountInfo);
update->Clear();
auto dict = std::make_unique<base::DictionaryValue>();
dict->SetString("account_id", email);
@@ -529,8 +526,7 @@ TEST_F(SigninManagerTest, VeryOldProfileGaiaIdMigration) {
PrefService* client_prefs = signin_client()->GetPrefs();
client_prefs->SetInteger(prefs::kAccountIdMigrationState,
AccountTrackerService::MIGRATION_NOT_STARTED);
- ListPrefUpdate update(client_prefs,
- AccountTrackerService::kAccountInfoPref);
+ ListPrefUpdate update(client_prefs, prefs::kAccountInfo);
update->Clear();
auto dict = std::make_unique<base::DictionaryValue>();
dict->SetString("account_id", email);
@@ -559,8 +555,7 @@ TEST_F(SigninManagerTest, GaiaIdMigrationCrashInTheMiddle) {
PrefService* client_prefs = signin_client()->GetPrefs();
client_prefs->SetInteger(prefs::kAccountIdMigrationState,
AccountTrackerService::MIGRATION_NOT_STARTED);
- ListPrefUpdate update(client_prefs,
- AccountTrackerService::kAccountInfoPref);
+ ListPrefUpdate update(client_prefs, prefs::kAccountInfo);
update->Clear();
auto dict = std::make_unique<base::DictionaryValue>();
dict->SetString("account_id", email);
diff --git a/chromium/components/signin/core/browser/signin_metrics.cc b/chromium/components/signin/core/browser/signin_metrics.cc
index 224ae0411b6..7c0bf8613fa 100644
--- a/chromium/components/signin/core/browser/signin_metrics.cc
+++ b/chromium/components/signin/core/browser/signin_metrics.cc
@@ -118,6 +118,10 @@ void RecordSigninUserActionForAccessPoint(AccessPoint access_point) {
base::RecordAction(
base::UserMetricsAction("Signin_Signin_FromMachineLogon"));
break;
+ case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromGoogleServicesSettings"));
+ break;
case AccessPoint::ACCESS_POINT_MAX:
NOTREACHED();
break;
@@ -186,6 +190,7 @@ void RecordSigninWithDefaultUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+ case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
NOTREACHED() << "Signin_SigninWithDefault_From* user actions"
<< " are not recorded for access_point "
<< static_cast<int>(access_point)
@@ -259,6 +264,7 @@ void RecordSigninNotDefaultUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+ case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
NOTREACHED() << "Signin_SigninNotDefault_From* user actions"
<< " are not recorded for access point "
<< static_cast<int>(access_point)
@@ -332,6 +338,7 @@ void RecordSigninNewAccountPreDiceUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+ case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
// These access points do not support personalized sign-in promos, so
// |Signin_SigninNewAccountPreDice_From*| user actions should not
// be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -416,6 +423,7 @@ void RecordSigninNewAccountNoExistingAccountUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+ case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
// These access points do not support personalized sign-in promos, so
// |Signin_SigninNewAccountNoExistingAccount_From*| user actions should
// not be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -496,6 +504,7 @@ void RecordSigninNewAccountExistingAccountUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+ case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
// These access points do not support personalized sign-in promos, so
// |Signin_SigninNewAccountExistingAccount_From*| user actions should not
// be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -945,6 +954,10 @@ void RecordSigninImpressionUserActionForAccessPoint(AccessPoint access_point) {
base::RecordAction(
base::UserMetricsAction("Signin_Impression_FromManageCardsBubble"));
break;
+ case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_Impression_FromGoogleServicesSettings"));
+ break;
case AccessPoint::ACCESS_POINT_CONTENT_AREA:
case AccessPoint::ACCESS_POINT_EXTENSIONS:
case AccessPoint::ACCESS_POINT_SUPERVISED_USER:
@@ -1079,6 +1092,7 @@ void RecordSigninImpressionWithAccountUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+ case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
NOTREACHED() << "Signin_Impression{With|WithNo}Account_From* user actions"
<< " are not recorded for access point "
<< static_cast<int>(access_point)
diff --git a/chromium/components/signin/core/browser/signin_metrics.h b/chromium/components/signin/core/browser/signin_metrics.h
index 3b52acd161d..dcd0aebc082 100644
--- a/chromium/components/signin/core/browser/signin_metrics.h
+++ b/chromium/components/signin/core/browser/signin_metrics.h
@@ -159,6 +159,7 @@ enum class AccessPoint : int {
ACCESS_POINT_SAVE_CARD_BUBBLE = 24,
ACCESS_POINT_MANAGE_CARDS_BUBBLE = 25,
ACCESS_POINT_MACHINE_LOGON = 26,
+ ACCESS_POINT_GOOGLE_SERVICES_SETTINGS = 27,
ACCESS_POINT_MAX, // This must be last.
};
@@ -342,7 +343,10 @@ enum class SourceForRefreshTokenOperation {
kDiceResponseHandler_Signin,
kDiceResponseHandler_Signout,
kDiceTurnOnSyncHelper_Abort,
- kMaxValue = kDiceTurnOnSyncHelper_Abort
+ kMachineLogon_CredentialProvider,
+ kTokenService_ExtractCredentials,
+
+ kMaxValue = kTokenService_ExtractCredentials
};
// Different types of reporting. This is used as a histogram suffix.
diff --git a/chromium/components/signin/core/browser/signin_metrics_unittest.cc b/chromium/components/signin/core/browser/signin_metrics_unittest.cc
index 72ed284a50e..ec4cb749f40 100644
--- a/chromium/components/signin/core/browser/signin_metrics_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_metrics_unittest.cc
@@ -106,6 +106,8 @@ class SigninMetricsTest : public ::testing::Test {
return "ManageCardsBubble";
case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
return "MachineLogon";
+ case AccessPoint::ACCESS_POINT_GOOGLE_SERVICES_SETTINGS:
+ return "GoogleServicesSettings";
case AccessPoint::ACCESS_POINT_MAX:
NOTREACHED();
return "";
diff --git a/chromium/components/signin/core/browser/signin_pref_names.cc b/chromium/components/signin/core/browser/signin_pref_names.cc
index 8de4eccd27b..c5923a59b12 100644
--- a/chromium/components/signin/core/browser/signin_pref_names.cc
+++ b/chromium/components/signin/core/browser/signin_pref_names.cc
@@ -17,6 +17,10 @@ const char kAccountConsistencyMirrorRequired[] =
// for possible values.
const char kAccountIdMigrationState[] = "account_id_migration_state";
+// Name of the preference property that persists the account information
+// tracked by this signin.
+const char kAccountInfo[] = "account_info";
+
// Boolean identifying whether reverse auto-login is enabled.
const char kAutologinEnabled[] = "autologin.enabled";
@@ -39,8 +43,8 @@ const char kGaiaCookiePeriodicReportTime[] = "gaia_cookie.periodic_report_time";
// eventually be fixed, allowing the removal of kGoogleServicesUserAccountId.
const char kGoogleServicesAccountId[] = "google.services.account_id";
-// The profile's hosted domain; empty if unset;
-// AccountTrackerService::kNoHostedDomainFound if there is none.
+// The profile's hosted domain; empty if unset; kNoHostedDomainFound if there
+// is none.
const char kGoogleServicesHostedDomain[] = "google.services.hosted_domain";
// Similar to kGoogleServicesLastUsername, this is the corresponding version of
@@ -86,6 +90,11 @@ const char kReverseAutologinRejectedEmailList[] =
// to the browser.
const char kSignedInTime[] = "signin.signedin_time";
+// Boolean indicating if this profile was signed in with information from a
+// credential provider.
+const char kSignedInWithCredentialProvider[] =
+ "signin.with_credential_provider";
+
// Boolean which stores if the user is allowed to signin to chrome.
const char kSigninAllowed[] = "signin.allowed";
diff --git a/chromium/components/signin/core/browser/signin_pref_names.h b/chromium/components/signin/core/browser/signin_pref_names.h
index 2ebafcbc7a9..61391ea9f6b 100644
--- a/chromium/components/signin/core/browser/signin_pref_names.h
+++ b/chromium/components/signin/core/browser/signin_pref_names.h
@@ -11,6 +11,7 @@ namespace prefs {
extern const char kAccountConsistencyMirrorRequired[];
#endif
extern const char kAccountIdMigrationState[];
+extern const char kAccountInfo[];
extern const char kAutologinEnabled[];
extern const char kGaiaCookieHash[];
extern const char kGaiaCookieChangedTime[];
@@ -25,6 +26,7 @@ extern const char kGoogleServicesUsername[];
extern const char kGoogleServicesUsernamePattern[];
extern const char kReverseAutologinRejectedEmailList[];
extern const char kSignedInTime[];
+extern const char kSignedInWithCredentialProvider[];
extern const char kSigninAllowed[];
extern const char kTokenServiceDiceCompatible[];
extern const char kTokenServiceExcludeAllSecondaryAccounts[];
diff --git a/chromium/components/signin/core/browser/signin_tracker.cc b/chromium/components/signin/core/browser/signin_tracker.cc
index 0a82a897a96..230b49eb9db 100644
--- a/chromium/components/signin/core/browser/signin_tracker.cc
+++ b/chromium/components/signin/core/browser/signin_tracker.cc
@@ -4,45 +4,36 @@
#include "components/signin/core/browser/signin_tracker.h"
-#include "components/signin/core/browser/gaia_cookie_manager_service.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "google_apis/gaia/gaia_constants.h"
-SigninTracker::SigninTracker(ProfileOAuth2TokenService* token_service,
- SigninManagerBase* signin_manager,
- GaiaCookieManagerService* cookie_manager_service,
+SigninTracker::SigninTracker(identity::IdentityManager* identity_manager,
Observer* observer)
- : token_service_(token_service),
- signin_manager_(signin_manager),
- cookie_manager_service_(cookie_manager_service),
- observer_(observer) {
+ : identity_manager_(identity_manager), observer_(observer) {
Initialize();
}
SigninTracker::~SigninTracker() {
- signin_manager_->RemoveObserver(this);
- token_service_->RemoveObserver(this);
- cookie_manager_service_->RemoveObserver(this);
+ identity_manager_->RemoveObserver(this);
}
void SigninTracker::Initialize() {
DCHECK(observer_);
- signin_manager_->AddObserver(this);
- token_service_->AddObserver(this);
- cookie_manager_service_->AddObserver(this);
+ identity_manager_->AddObserver(this);
}
-void SigninTracker::GoogleSigninSucceeded(const AccountInfo& account_info) {
- if (token_service_->RefreshTokenIsAvailable(account_info.account_id))
+void SigninTracker::OnPrimaryAccountSet(const AccountInfo& account_info) {
+ if (identity_manager_->HasAccountWithRefreshToken(account_info.account_id))
observer_->SigninSuccess();
}
-void SigninTracker::GoogleSigninFailed(const GoogleServiceAuthError& error) {
+void SigninTracker::OnPrimaryAccountSigninFailed(
+ const GoogleServiceAuthError& error) {
observer_->SigninFailed(error);
}
-void SigninTracker::OnRefreshTokenAvailable(const std::string& account_id) {
- if (account_id != signin_manager_->GetAuthenticatedAccountId())
+void SigninTracker::OnRefreshTokenUpdatedForAccount(
+ const AccountInfo& account_info) {
+ if (account_info.account_id != identity_manager_->GetPrimaryAccountId())
return;
observer_->SigninSuccess();
diff --git a/chromium/components/signin/core/browser/signin_tracker.h b/chromium/components/signin/core/browser/signin_tracker.h
index cb857e3afd7..0e6e8c5bb35 100644
--- a/chromium/components/signin/core/browser/signin_tracker.h
+++ b/chromium/components/signin/core/browser/signin_tracker.h
@@ -8,17 +8,14 @@
#include <memory>
#include "base/macros.h"
-#include "components/signin/core/browser/gaia_cookie_manager_service.h"
-#include "components/signin/core/browser/signin_manager.h"
#include "google_apis/gaia/google_service_auth_error.h"
-
-class ProfileOAuth2TokenService;
+#include "services/identity/public/cpp/identity_manager.h"
// The signin flow logic is spread across several classes with varying
// responsibilities:
//
-// SigninTracker (this class) - This class listens to notifications from various
-// services (SigninManager, OAuth2TokenService) and coalesces them into
+// SigninTracker (this class) - This class listens to notifications from the
+// IdentityManager services and coalesces them into
// notifications for the UI layer. This is the class that encapsulates the logic
// that determines whether a user is fully logged in or not, and exposes
// callbacks so various pieces of the UI (OneClickSyncStarter) can track the
@@ -35,25 +32,21 @@ class ProfileOAuth2TokenService;
// (a KeyedService that keeps track of the currently visible
// login UI).
//
-// SigninManager - Records the currently-logged-in user and handles all
+// IdentityManager - Records the currently-logged-in user and handles all
// interaction with the GAIA backend during the signin process. Unlike
-// SigninTracker, SigninManager only knows about the GAIA login state and is
+// SigninTracker, IdentityManager only knows about the GAIA login state and is
// not aware of the state of any signed in services.
-//
-// OAuth2TokenService - Maintains and manages OAuth2 tokens for the accounts
-// connected to this profile.
-//
-// GaiaCookieManagerService - Responsible for adding or removing cookies from
-// the cookie jar from the browser process. A single source of information about
-// GAIA cookies in the cookie jar that are fetchable via /ListAccounts.
+// What is more, IdentityManager also maintains and manages OAuth2 tokens for
+// the accounts connected to this profile.
+// Last, the IdentityManager is also responsible for adding or removing cookies
+// from the cookie jar from the browser process. A single source of information
+// about GAIA cookies in the cookie jar that are fetchable via /ListAccounts.
//
// ProfileSyncService - Provides the external API for interacting with the
// sync framework. Listens for notifications for tokens to know when to startup
// sync, and provides an Observer interface to notify the UI layer of changes
// in sync state so they can be reflected in the UI.
-class SigninTracker : public SigninManagerBase::Observer,
- public OAuth2TokenService::Observer,
- public GaiaCookieManagerService::Observer {
+class SigninTracker : public identity::IdentityManager::Observer {
public:
class Observer {
public:
@@ -73,32 +66,26 @@ class SigninTracker : public SigninManagerBase::Observer,
// instances with the exception of |account_reconcilor| must be non-null and
// must outlive the SigninTracker. |account_reconcilor| will be used if it is
// non-null.
- SigninTracker(ProfileOAuth2TokenService* token_service,
- SigninManagerBase* signin_manager,
- GaiaCookieManagerService* cookie_manager_service,
+ SigninTracker(identity::IdentityManager* identity_manager,
Observer* observer);
~SigninTracker() override;
- // SigninManagerBase::Observer implementation.
- void GoogleSigninSucceeded(const AccountInfo& account_info) override;
- void GoogleSigninFailed(const GoogleServiceAuthError& error) override;
-
- // OAuth2TokenService::Observer implementation.
- void OnRefreshTokenAvailable(const std::string& account_id) override;
+ // identity::IdentityManager::Observer implementation.
+ void OnPrimaryAccountSet(const AccountInfo& account_info) override;
+ void OnPrimaryAccountSigninFailed(
+ const GoogleServiceAuthError& error) override;
+ void OnRefreshTokenUpdatedForAccount(
+ const AccountInfo& account_info) override;
+ void OnAddAccountToCookieCompleted(
+ const std::string& account_id,
+ const GoogleServiceAuthError& error) override;
private:
// Initializes this by adding notifications and observers.
void Initialize();
- // GaiaCookieManagerService::Observer implementation.
- void OnAddAccountToCookieCompleted(
- const std::string& account_id,
- const GoogleServiceAuthError& error) override;
-
// The classes whose collective signin status we are tracking.
- ProfileOAuth2TokenService* token_service_;
- SigninManagerBase* signin_manager_;
- GaiaCookieManagerService* cookie_manager_service_;
+ identity::IdentityManager* identity_manager_;
// Weak pointer to the observer we call when the signin state changes.
Observer* observer_;
diff --git a/chromium/components/signin/core/browser/signin_tracker_unittest.cc b/chromium/components/signin/core/browser/signin_tracker_unittest.cc
index 78cc5424b6f..e6114a3729c 100644
--- a/chromium/components/signin/core/browser/signin_tracker_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_tracker_unittest.cc
@@ -5,18 +5,11 @@
#include "components/signin/core/browser/signin_tracker.h"
#include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
+#include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
-#include "components/signin/core/browser/account_consistency_method.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
-#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
-#include "components/signin/core/browser/fake_signin_manager.h"
-#include "components/signin/core/browser/signin_switches.h"
-#include "components/signin/core/browser/test_signin_client.h"
-#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/google_service_auth_error.h"
+#include "services/identity/public/cpp/identity_test_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -49,41 +42,16 @@ class MockObserver : public SigninTracker::Observer {
class SigninTrackerTest : public testing::Test {
public:
- SigninTrackerTest()
- : signin_client_(&pref_service_),
- fake_oauth2_token_service_(&pref_service_),
- fake_gaia_cookie_manager_service_(&fake_oauth2_token_service_,
- &signin_client_),
-#if defined(OS_CHROMEOS)
- fake_signin_manager_(&signin_client_, &account_tracker_) {
-#else
- fake_signin_manager_(&signin_client_,
- &fake_oauth2_token_service_,
- &account_tracker_,
- &fake_gaia_cookie_manager_service_) {
-#endif
-
- AccountTrackerService::RegisterPrefs(pref_service_.registry());
- SigninManagerBase::RegisterProfilePrefs(pref_service_.registry());
- SigninManagerBase::RegisterPrefs(pref_service_.registry());
-
- account_tracker_.Initialize(&pref_service_, base::FilePath());
-
+ SigninTrackerTest() {
tracker_ = std::make_unique<SigninTracker>(
- &fake_oauth2_token_service_, &fake_signin_manager_,
- &fake_gaia_cookie_manager_service_, &observer_);
+ identity_test_env_.identity_manager(), &observer_);
}
~SigninTrackerTest() override { tracker_.reset(); }
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment task_environment_;
std::unique_ptr<SigninTracker> tracker_;
- sync_preferences::TestingPrefServiceSyncable pref_service_;
- AccountTrackerService account_tracker_;
- TestSigninClient signin_client_;
- FakeProfileOAuth2TokenService fake_oauth2_token_service_;
- FakeGaiaCookieManagerService fake_gaia_cookie_manager_service_;
- FakeSigninManagerForTesting fake_signin_manager_;
+ identity::IdentityTestEnvironment identity_test_env_;
MockObserver observer_;
};
@@ -96,7 +64,8 @@ TEST_F(SigninTrackerTest, SignInFails) {
EXPECT_CALL(observer_, SigninSuccess()).Times(0);
EXPECT_CALL(observer_, SigninFailed(error));
- fake_signin_manager_.FailSignin(error);
+ // Mimic calling IdentityManager::GoogleSigninFailed().
+ tracker_->OnPrimaryAccountSigninFailed(error);
}
#endif // !defined(OS_CHROMEOS)
@@ -104,11 +73,8 @@ TEST_F(SigninTrackerTest, SignInSucceeds) {
EXPECT_CALL(observer_, SigninSuccess());
EXPECT_CALL(observer_, SigninFailed(_)).Times(0);
- std::string gaia_id = "gaia_id";
std::string email = "user@gmail.com";
- std::string account_id = account_tracker_.SeedAccountInfo(gaia_id, email);
- fake_signin_manager_.SetAuthenticatedAccountInfo(gaia_id, email);
- fake_oauth2_token_service_.UpdateCredentials(account_id, "refresh_token");
+ identity_test_env_.MakePrimaryAccountAvailable(email);
}
#if !defined(OS_CHROMEOS)
@@ -116,10 +82,8 @@ TEST_F(SigninTrackerTest, SignInSucceedsWithExistingAccount) {
EXPECT_CALL(observer_, SigninSuccess());
EXPECT_CALL(observer_, SigninFailed(_)).Times(0);
- std::string gaia_id = "gaia_id";
std::string email = "user@gmail.com";
- std::string account_id = account_tracker_.SeedAccountInfo(gaia_id, email);
- fake_oauth2_token_service_.UpdateCredentials(account_id, "refresh_token");
- fake_signin_manager_.SignIn(gaia_id, email, std::string());
+ AccountInfo account_info = identity_test_env_.MakeAccountAvailable(email);
+ identity_test_env_.SetPrimaryAccount(account_info.email);
}
#endif
diff --git a/chromium/components/signin/core/browser/ubertoken_fetcher.cc b/chromium/components/signin/core/browser/ubertoken_fetcher.cc
new file mode 100644
index 00000000000..6eea8ba9c4d
--- /dev/null
+++ b/chromium/components/signin/core/browser/ubertoken_fetcher.cc
@@ -0,0 +1,15 @@
+// Copyright 2019 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 "components/signin/core/browser/ubertoken_fetcher.h"
+
+namespace signin {
+
+// While defining providing an implementation to pure virtual methods is rarely
+// useful, one must define a pure virtual destructor. This is because the
+// destructor of a base class is always called when a derived object is
+// destroyed. Failing to define it will cause a link error.
+UbertokenFetcher::~UbertokenFetcher() {}
+
+} // namespace signin
diff --git a/chromium/components/signin/core/browser/ubertoken_fetcher.h b/chromium/components/signin/core/browser/ubertoken_fetcher.h
new file mode 100644
index 00000000000..cc4f1691e5c
--- /dev/null
+++ b/chromium/components/signin/core/browser/ubertoken_fetcher.h
@@ -0,0 +1,35 @@
+// Copyright 2019 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 COMPONENTS_SIGNIN_CORE_BROWSER_UBERTOKEN_FETCHER_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_UBERTOKEN_FETCHER_H_
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/macros.h"
+
+class GoogleServiceAuthError;
+
+namespace signin {
+
+// Opaque interface that fetches ubertokens for a given account. Clients must
+// go through IdentityManager to create a functioning instance.
+class UbertokenFetcher {
+ public:
+ using CompletionCallback =
+ base::OnceCallback<void(GoogleServiceAuthError error,
+ const std::string& token)>;
+
+ // Constructs an instance and start fetching the token for |account_id|.
+ UbertokenFetcher() = default;
+ virtual ~UbertokenFetcher() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(UbertokenFetcher);
+};
+
+} // namespace signin
+
+#endif // COMPONENTS_SIGNIN_CORE_BROWSER_UBERTOKEN_FETCHER_H_
diff --git a/chromium/components/signin/core/browser/ubertoken_fetcher_impl.cc b/chromium/components/signin/core/browser/ubertoken_fetcher_impl.cc
new file mode 100644
index 00000000000..53c3f7dd5ec
--- /dev/null
+++ b/chromium/components/signin/core/browser/ubertoken_fetcher_impl.cc
@@ -0,0 +1,156 @@
+// Copyright 2014 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 "components/signin/core/browser/ubertoken_fetcher_impl.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/rand_util.h"
+#include "base/time/time.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
+
+namespace {
+std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcher(
+ gaia::GaiaSource source,
+ GaiaAuthConsumer* consumer,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+ return std::make_unique<GaiaAuthFetcher>(consumer, source,
+ url_loader_factory);
+}
+} // namespace
+
+namespace signin {
+
+const int UbertokenFetcherImpl::kMaxRetries = 3;
+
+UbertokenFetcherImpl::UbertokenFetcherImpl(
+ const std::string& account_id,
+ OAuth2TokenService* token_service,
+ CompletionCallback ubertoken_callback,
+ gaia::GaiaSource source,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ bool is_bound_to_channel_id)
+ : UbertokenFetcherImpl(account_id,
+ /*access_token=*/"",
+ token_service,
+ std::move(ubertoken_callback),
+ url_loader_factory,
+ base::BindRepeating(CreateGaiaAuthFetcher, source),
+ is_bound_to_channel_id) {}
+
+UbertokenFetcherImpl::UbertokenFetcherImpl(
+ const std::string& account_id,
+ const std::string& access_token,
+ OAuth2TokenService* token_service,
+ CompletionCallback ubertoken_callback,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ GaiaAuthFetcherFactory factory,
+ bool is_bound_to_channel_id)
+ : OAuth2TokenService::Consumer("uber_token_fetcher"),
+ token_service_(token_service),
+ ubertoken_callback_(std::move(ubertoken_callback)),
+ url_loader_factory_(url_loader_factory),
+ is_bound_to_channel_id_(is_bound_to_channel_id),
+ gaia_auth_fetcher_factory_(factory),
+ account_id_(account_id),
+ access_token_(access_token),
+ retry_number_(0),
+ second_access_token_request_(false) {
+ DCHECK(!account_id.empty());
+ DCHECK(token_service);
+ DCHECK(!ubertoken_callback_.is_null());
+ DCHECK(url_loader_factory);
+
+ if (access_token_.empty()) {
+ RequestAccessToken();
+ return;
+ }
+
+ ExchangeTokens();
+}
+
+UbertokenFetcherImpl::~UbertokenFetcherImpl() {}
+
+void UbertokenFetcherImpl::OnUberAuthTokenSuccess(const std::string& token) {
+ std::move(ubertoken_callback_)
+ .Run(GoogleServiceAuthError::AuthErrorNone(), token);
+}
+
+void UbertokenFetcherImpl::OnUberAuthTokenFailure(
+ const GoogleServiceAuthError& error) {
+ // Retry only transient errors.
+ bool should_retry =
+ error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
+ error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE;
+ if (should_retry) {
+ if (retry_number_ < kMaxRetries) {
+ // Calculate an exponential backoff with randomness of less than 1 sec.
+ double backoff = base::RandDouble() + (1 << retry_number_);
+ ++retry_number_;
+ UMA_HISTOGRAM_ENUMERATION("Signin.UberTokenRetry", error.state(),
+ GoogleServiceAuthError::NUM_STATES);
+ retry_timer_.Stop();
+ retry_timer_.Start(FROM_HERE, base::TimeDelta::FromSecondsD(backoff),
+ this, &UbertokenFetcherImpl::ExchangeTokens);
+ return;
+ }
+ } else {
+ // The access token is invalid. Tell the token service.
+ OAuth2TokenService::ScopeSet scopes;
+ scopes.insert(GaiaConstants::kOAuth1LoginScope);
+ token_service_->InvalidateAccessToken(account_id_, scopes, access_token_);
+
+ // In case the access was just stale, try one more time.
+ if (!second_access_token_request_) {
+ second_access_token_request_ = true;
+ RequestAccessToken();
+ return;
+ }
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("Signin.UberTokenFailure", error.state(),
+ GoogleServiceAuthError::NUM_STATES);
+ std::move(ubertoken_callback_).Run(error, /*access_token=*/std::string());
+}
+
+void UbertokenFetcherImpl::OnGetTokenSuccess(
+ const OAuth2TokenService::Request* request,
+ const OAuth2AccessTokenConsumer::TokenResponse& token_response) {
+ DCHECK(!token_response.access_token.empty());
+ access_token_ = token_response.access_token;
+ access_token_request_.reset();
+ ExchangeTokens();
+}
+
+void UbertokenFetcherImpl::OnGetTokenFailure(
+ const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) {
+ access_token_request_.reset();
+ std::move(ubertoken_callback_).Run(error, /*access_token=*/std::string());
+}
+
+void UbertokenFetcherImpl::RequestAccessToken() {
+ retry_number_ = 0;
+ gaia_auth_fetcher_.reset();
+ retry_timer_.Stop();
+
+ OAuth2TokenService::ScopeSet scopes;
+ scopes.insert(GaiaConstants::kOAuth1LoginScope);
+ access_token_request_ =
+ token_service_->StartRequest(account_id_, scopes, this);
+}
+
+void UbertokenFetcherImpl::ExchangeTokens() {
+ gaia_auth_fetcher_ =
+ gaia_auth_fetcher_factory_.Run(this, url_loader_factory_);
+ gaia_auth_fetcher_->StartTokenFetchForUberAuthExchange(
+ access_token_, is_bound_to_channel_id_);
+}
+
+} // namespace signin
diff --git a/chromium/components/signin/core/browser/ubertoken_fetcher_impl.h b/chromium/components/signin/core/browser/ubertoken_fetcher_impl.h
new file mode 100644
index 00000000000..9a07e0f1d1c
--- /dev/null
+++ b/chromium/components/signin/core/browser/ubertoken_fetcher_impl.h
@@ -0,0 +1,108 @@
+// Copyright 2014 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 COMPONENTS_SIGNIN_CORE_BROWSER_UBERTOKEN_FETCHER_IMPL_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_UBERTOKEN_FETCHER_IMPL_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/timer/timer.h"
+#include "components/signin/core/browser/ubertoken_fetcher.h"
+#include "google_apis/gaia/gaia_auth_consumer.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+
+// Allow to retrieves an uber-auth token for the user. This class uses the
+// |OAuth2TokenService| and considers that the user is already logged in. It
+// will use the OAuth2 access token to generate the uber-auth token.
+//
+// This class should be used on a single thread, but it can be whichever thread
+// that you like.
+//
+// This class can handle one request at a time.
+
+class GoogleServiceAuthError;
+
+namespace network {
+class SharedURLLoaderFactory;
+}
+
+namespace signin {
+
+using GaiaAuthFetcherFactory =
+ base::RepeatingCallback<std::unique_ptr<GaiaAuthFetcher>(
+ GaiaAuthConsumer*,
+ scoped_refptr<network::SharedURLLoaderFactory>)>;
+
+// Allows to retrieve an uber-auth token.
+class UbertokenFetcherImpl : public UbertokenFetcher,
+ public GaiaAuthConsumer,
+ public OAuth2TokenService::Consumer {
+ public:
+ // Maximum number of retries to get the uber-auth token before giving up.
+ static const int kMaxRetries;
+
+ using CompletionCallback =
+ base::OnceCallback<void(GoogleServiceAuthError error,
+ const std::string& token)>;
+
+ // Constructs an instance and starts fetching the access token and ubertoken
+ // sequencially for |account_id|.
+ UbertokenFetcherImpl(
+ const std::string& account_id,
+ OAuth2TokenService* token_service,
+ CompletionCallback ubertoken_callback,
+ gaia::GaiaSource source,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ bool is_bound_to_channel_id = true);
+
+ // Constructs an instance and starts fetching the ubertoken for |account_id|.
+ UbertokenFetcherImpl(
+ const std::string& account_id,
+ const std::string& access_token,
+ OAuth2TokenService* token_service,
+ CompletionCallback ubertoken_callback,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ GaiaAuthFetcherFactory factory,
+ bool is_bound_to_channel_id = true);
+ ~UbertokenFetcherImpl() override;
+
+ // Overriden from GaiaAuthConsumer
+ void OnUberAuthTokenSuccess(const std::string& token) override;
+ void OnUberAuthTokenFailure(const GoogleServiceAuthError& error) override;
+
+ // Overriden from OAuth2TokenService::Consumer:
+ void OnGetTokenSuccess(
+ const OAuth2TokenService::Request* request,
+ const OAuth2AccessTokenConsumer::TokenResponse& token_response) override;
+ void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) override;
+
+ private:
+ // Request a login-scoped access token from the token service.
+ void RequestAccessToken();
+
+ // Exchanges an oauth2 access token for an uber-auth token.
+ void ExchangeTokens();
+
+ OAuth2TokenService* token_service_;
+ CompletionCallback ubertoken_callback_;
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+ bool is_bound_to_channel_id_; // defaults to true
+ GaiaAuthFetcherFactory gaia_auth_fetcher_factory_;
+ std::unique_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
+ std::unique_ptr<OAuth2TokenService::Request> access_token_request_;
+ std::string account_id_;
+ std::string access_token_;
+ int retry_number_;
+ base::OneShotTimer retry_timer_;
+ bool second_access_token_request_;
+
+ DISALLOW_COPY_AND_ASSIGN(UbertokenFetcherImpl);
+};
+
+} // namespace signin
+
+#endif // COMPONENTS_SIGNIN_CORE_BROWSER_UBERTOKEN_FETCHER_IMPL_H_
diff --git a/chromium/components/signin/core/browser/ubertoken_fetcher_impl_unittest.cc b/chromium/components/signin/core/browser/ubertoken_fetcher_impl_unittest.cc
new file mode 100644
index 00000000000..b9ce26d86f9
--- /dev/null
+++ b/chromium/components/signin/core/browser/ubertoken_fetcher_impl_unittest.cc
@@ -0,0 +1,179 @@
+// Copyright 2014 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 "components/signin/core/browser/ubertoken_fetcher_impl.h"
+
+#include <memory>
+
+#include "base/memory/ref_counted.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "google_apis/gaia/fake_oauth2_token_service.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kTestAccountId[] = "test@gmail.com";
+
+class MockUbertokenConsumer {
+ public:
+ MockUbertokenConsumer()
+ : nb_correct_token_(0),
+ last_error_(GoogleServiceAuthError::AuthErrorNone()),
+ nb_error_(0) {}
+ virtual ~MockUbertokenConsumer() = default;
+
+ void OnUbertokenFetchComplete(GoogleServiceAuthError error,
+ const std::string& token) {
+ if (error != GoogleServiceAuthError::AuthErrorNone()) {
+ last_error_ = error;
+ ++nb_error_;
+ return;
+ }
+
+ last_token_ = token;
+ ++nb_correct_token_;
+ }
+
+ std::string last_token_;
+ int nb_correct_token_;
+ GoogleServiceAuthError last_error_;
+ int nb_error_;
+};
+
+} // namespace
+
+class UbertokenFetcherImplTest : public testing::Test {
+ public:
+ UbertokenFetcherImplTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::UI),
+ test_shared_loader_factory_(
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ &url_loader_factory_)) {
+ fetcher_ = std::make_unique<signin::UbertokenFetcherImpl>(
+ kTestAccountId, &token_service_,
+ base::BindOnce(&MockUbertokenConsumer::OnUbertokenFetchComplete,
+ base::Unretained(&consumer_)),
+ gaia::GaiaSource::kChrome, test_shared_loader_factory_);
+ }
+
+ protected:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ FakeOAuth2TokenService token_service_;
+ network::TestURLLoaderFactory url_loader_factory_;
+ scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
+ MockUbertokenConsumer consumer_;
+ std::unique_ptr<signin::UbertokenFetcherImpl> fetcher_;
+};
+
+TEST_F(UbertokenFetcherImplTest, Basic) {}
+
+TEST_F(UbertokenFetcherImplTest, Success) {
+ fetcher_->OnGetTokenSuccess(NULL,
+ OAuth2AccessTokenConsumer::TokenResponse(
+ "accessToken", base::Time(), std::string()));
+ fetcher_->OnUberAuthTokenSuccess("uberToken");
+
+ EXPECT_EQ(0, consumer_.nb_error_);
+ EXPECT_EQ(1, consumer_.nb_correct_token_);
+ EXPECT_EQ("uberToken", consumer_.last_token_);
+}
+
+TEST_F(UbertokenFetcherImplTest, NoRefreshToken) {
+ GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
+ fetcher_->OnGetTokenFailure(NULL, error);
+
+ EXPECT_EQ(1, consumer_.nb_error_);
+ EXPECT_EQ(0, consumer_.nb_correct_token_);
+}
+
+TEST_F(UbertokenFetcherImplTest, FailureToGetAccessToken) {
+ GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
+ fetcher_->OnGetTokenFailure(NULL, error);
+
+ EXPECT_EQ(1, consumer_.nb_error_);
+ EXPECT_EQ(0, consumer_.nb_correct_token_);
+ EXPECT_EQ("", consumer_.last_token_);
+}
+
+TEST_F(UbertokenFetcherImplTest, TransientFailureEventualFailure) {
+ GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
+ fetcher_->OnGetTokenSuccess(NULL,
+ OAuth2AccessTokenConsumer::TokenResponse(
+ "accessToken", base::Time(), std::string()));
+
+ for (int i = 0; i < signin::UbertokenFetcherImpl::kMaxRetries; ++i) {
+ fetcher_->OnUberAuthTokenFailure(error);
+ EXPECT_EQ(0, consumer_.nb_error_);
+ EXPECT_EQ(0, consumer_.nb_correct_token_);
+ EXPECT_EQ("", consumer_.last_token_);
+ }
+
+ fetcher_->OnUberAuthTokenFailure(error);
+ EXPECT_EQ(1, consumer_.nb_error_);
+ EXPECT_EQ(0, consumer_.nb_correct_token_);
+ EXPECT_EQ("", consumer_.last_token_);
+}
+
+TEST_F(UbertokenFetcherImplTest, TransientFailureEventualSuccess) {
+ GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
+ fetcher_->OnGetTokenSuccess(NULL,
+ OAuth2AccessTokenConsumer::TokenResponse(
+ "accessToken", base::Time(), std::string()));
+
+ for (int i = 0; i < signin::UbertokenFetcherImpl::kMaxRetries; ++i) {
+ fetcher_->OnUberAuthTokenFailure(error);
+ EXPECT_EQ(0, consumer_.nb_error_);
+ EXPECT_EQ(0, consumer_.nb_correct_token_);
+ EXPECT_EQ("", consumer_.last_token_);
+ }
+
+ fetcher_->OnUberAuthTokenSuccess("uberToken");
+ EXPECT_EQ(0, consumer_.nb_error_);
+ EXPECT_EQ(1, consumer_.nb_correct_token_);
+ EXPECT_EQ("uberToken", consumer_.last_token_);
+}
+
+TEST_F(UbertokenFetcherImplTest, PermanentFailureEventualFailure) {
+ fetcher_->OnGetTokenSuccess(NULL,
+ OAuth2AccessTokenConsumer::TokenResponse(
+ "accessToken", base::Time(), std::string()));
+
+ GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
+ fetcher_->OnUberAuthTokenFailure(error);
+ EXPECT_EQ(0, consumer_.nb_error_);
+ EXPECT_EQ(0, consumer_.nb_correct_token_);
+ EXPECT_EQ("", consumer_.last_token_);
+
+ fetcher_->OnGetTokenSuccess(NULL,
+ OAuth2AccessTokenConsumer::TokenResponse(
+ "accessToken", base::Time(), std::string()));
+ fetcher_->OnUberAuthTokenFailure(error);
+ EXPECT_EQ(1, consumer_.nb_error_);
+ EXPECT_EQ(0, consumer_.nb_correct_token_);
+ EXPECT_EQ("", consumer_.last_token_);
+}
+
+TEST_F(UbertokenFetcherImplTest, PermanentFailureEventualSuccess) {
+ GoogleServiceAuthError error(GoogleServiceAuthError::USER_NOT_SIGNED_UP);
+ fetcher_->OnGetTokenSuccess(NULL,
+ OAuth2AccessTokenConsumer::TokenResponse(
+ "accessToken", base::Time(), std::string()));
+
+ fetcher_->OnUberAuthTokenFailure(error);
+ EXPECT_EQ(0, consumer_.nb_error_);
+ EXPECT_EQ(0, consumer_.nb_correct_token_);
+ EXPECT_EQ("", consumer_.last_token_);
+
+ fetcher_->OnGetTokenSuccess(NULL,
+ OAuth2AccessTokenConsumer::TokenResponse(
+ "accessToken", base::Time(), std::string()));
+ fetcher_->OnUberAuthTokenSuccess("uberToken");
+ EXPECT_EQ(0, consumer_.nb_error_);
+ EXPECT_EQ(1, consumer_.nb_correct_token_);
+ EXPECT_EQ("uberToken", consumer_.last_token_);
+}
diff --git a/chromium/components/signin/ios/DEPS b/chromium/components/signin/ios/DEPS
index 4dd63070bb3..bb46705add5 100644
--- a/chromium/components/signin/ios/DEPS
+++ b/chromium/components/signin/ios/DEPS
@@ -1,4 +1,5 @@
include_rules = [
"+ios/web/public",
+ "+services/identity/public/cpp",
"+third_party/ocmock",
]
diff --git a/chromium/components/signin/ios/browser/BUILD.gn b/chromium/components/signin/ios/browser/BUILD.gn
index 9a5285b7585..088e53e3f0b 100644
--- a/chromium/components/signin/ios/browser/BUILD.gn
+++ b/chromium/components/signin/ios/browser/BUILD.gn
@@ -10,8 +10,6 @@ source_set("browser") {
"manage_accounts_delegate.h",
"merge_session_observer_bridge.h",
"merge_session_observer_bridge.mm",
- "oauth2_token_service_observer_bridge.h",
- "oauth2_token_service_observer_bridge.mm",
"profile_oauth2_token_service_ios_delegate.h",
"profile_oauth2_token_service_ios_delegate.mm",
"profile_oauth2_token_service_ios_provider.h",
@@ -31,6 +29,7 @@ source_set("browser") {
"//google_apis",
"//ios/web",
"//net",
+ "//services/identity/public/cpp:cpp",
]
}
@@ -78,11 +77,12 @@ source_set("unit_tests") {
":test_support",
"//components/prefs:test_support",
"//components/signin/core/browser",
- "//components/signin/core/browser:test_support",
+ "//components/signin/core/browser:internals_test_support",
"//components/sync_preferences:test_support",
"//ios/web",
"//ios/web/public/test",
"//ios/web/public/test/fakes",
+ "//services/identity/public/cpp:test_support",
"//third_party/ocmock",
]
}
diff --git a/chromium/components/signin/ios/browser/account_consistency_service.h b/chromium/components/signin/ios/browser/account_consistency_service.h
index 4488de9d378..e7ebe2345e7 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service.h
+++ b/chromium/components/signin/ios/browser/account_consistency_service.h
@@ -18,9 +18,9 @@
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/signin/core/browser/gaia_cookie_manager_service.h"
-#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/ios/browser/active_state_manager.h"
#import "components/signin/ios/browser/manage_accounts_delegate.h"
+#import "services/identity/public/cpp/identity_manager.h"
namespace web {
class BrowserState;
@@ -41,7 +41,7 @@ class SigninClient;
// This is currently only used when WKWebView is enabled.
class AccountConsistencyService : public KeyedService,
public GaiaCookieManagerService::Observer,
- public SigninManagerBase::Observer,
+ public identity::IdentityManager::Observer,
public ActiveStateManager::Observer {
public:
// Name of the preference property that persists the domains that have a
@@ -54,7 +54,7 @@ class AccountConsistencyService : public KeyedService,
scoped_refptr<content_settings::CookieSettings> cookie_settings,
GaiaCookieManagerService* gaia_cookie_manager_service,
SigninClient* signin_client,
- SigninManager* signin_manager);
+ identity::IdentityManager* identity_manager);
~AccountConsistencyService() override;
// Registers the preferences used by AccountConsistencyService.
@@ -155,9 +155,10 @@ class AccountConsistencyService : public KeyedService,
const std::vector<gaia::ListedAccount>& signed_out_accounts,
const GoogleServiceAuthError& error) override;
- // SigninManagerBase::Observer implementation.
- void GoogleSigninSucceeded(const AccountInfo& account_info) override;
- void GoogleSignedOut(const AccountInfo& account_info) override;
+ // IdentityManager::Observer implementation.
+ void OnPrimaryAccountSet(const AccountInfo& account_info) override;
+ void OnPrimaryAccountCleared(
+ const AccountInfo& previous_account_info) override;
// ActiveStateManager::Observer implementation.
void OnActive() override;
@@ -176,8 +177,9 @@ class AccountConsistencyService : public KeyedService,
GaiaCookieManagerService* gaia_cookie_manager_service_;
// Signin client, used to access prefs.
SigninClient* signin_client_;
- // Signin manager, observed to be notified of signin and signout events.
- SigninManager* signin_manager_;
+ // Identity manager, observed to be notified of primary account signin and
+ // signout events.
+ identity::IdentityManager* identity_manager_;
// Whether a CHROME_CONNECTED cookie request is currently being applied.
bool applying_cookie_requests_;
diff --git a/chromium/components/signin/ios/browser/account_consistency_service.mm b/chromium/components/signin/ios/browser/account_consistency_service.mm
index 39095fa67ef..f4de0d48b49 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service.mm
+++ b/chromium/components/signin/ios/browser/account_consistency_service.mm
@@ -221,19 +221,19 @@ AccountConsistencyService::AccountConsistencyService(
scoped_refptr<content_settings::CookieSettings> cookie_settings,
GaiaCookieManagerService* gaia_cookie_manager_service,
SigninClient* signin_client,
- SigninManager* signin_manager)
+ identity::IdentityManager* identity_manager)
: browser_state_(browser_state),
account_reconcilor_(account_reconcilor),
cookie_settings_(cookie_settings),
gaia_cookie_manager_service_(gaia_cookie_manager_service),
signin_client_(signin_client),
- signin_manager_(signin_manager),
+ identity_manager_(identity_manager),
applying_cookie_requests_(false) {
gaia_cookie_manager_service_->AddObserver(this);
- signin_manager_->AddObserver(this);
+ identity_manager_->AddObserver(this);
ActiveStateManager::FromBrowserState(browser_state_)->AddObserver(this);
LoadFromPrefs();
- if (signin_manager_->IsAuthenticated()) {
+ if (identity_manager_->HasPrimaryAccount()) {
AddChromeConnectedCookies();
} else {
RemoveChromeConnectedCookies(base::OnceClosure());
@@ -333,7 +333,7 @@ void AccountConsistencyService::LoadFromPrefs() {
void AccountConsistencyService::Shutdown() {
gaia_cookie_manager_service_->RemoveObserver(this);
- signin_manager_->RemoveObserver(this);
+ identity_manager_->RemoveObserver(this);
ActiveStateManager::FromBrowserState(browser_state_)->RemoveObserver(this);
ResetWKWebView();
web_state_handlers_.clear();
@@ -363,7 +363,7 @@ void AccountConsistencyService::ApplyCookieRequests() {
switch (cookie_requests_.front().request_type) {
case ADD_CHROME_CONNECTED_COOKIE:
cookie_value = signin::BuildMirrorRequestCookieIfPossible(
- url, signin_manager_->GetAuthenticatedAccountInfo().gaia,
+ url, identity_manager_->GetPrimaryAccountInfo().gaia,
signin::AccountConsistencyMethod::kMirror, cookie_settings_.get(),
signin::PROFILE_MODE_DEFAULT);
if (cookie_value.empty()) {
@@ -490,13 +490,13 @@ void AccountConsistencyService::OnGaiaAccountsInCookieUpdated(
AddChromeConnectedCookies();
}
-void AccountConsistencyService::GoogleSigninSucceeded(
+void AccountConsistencyService::OnPrimaryAccountSet(
const AccountInfo& account_info) {
AddChromeConnectedCookies();
}
-void AccountConsistencyService::GoogleSignedOut(
- const AccountInfo& account_info) {
+void AccountConsistencyService::OnPrimaryAccountCleared(
+ const AccountInfo& previous_account_info) {
// There is not need to remove CHROME_CONNECTED cookies on |GoogleSignedOut|
// events as these cookies will be removed by the GaiaCookieManagerServer
// right before fetching the Gaia logout request.
diff --git a/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm b/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm
index 4193365a296..1a7a24a2303 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm
+++ b/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm
@@ -14,6 +14,7 @@
#include "components/signin/core/browser/account_reconcilor.h"
#include "components/signin/core/browser/account_reconcilor_delegate.h"
#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
#include "components/signin/core/browser/fake_signin_manager.h"
#include "components/signin/core/browser/gaia_cookie_manager_service.h"
@@ -24,6 +25,8 @@
#import "ios/web/public/test/fakes/test_web_state.h"
#include "ios/web/public/test/test_web_thread_bundle.h"
#include "ios/web/public/web_state/web_state_policy_decider.h"
+#import "services/identity/public/cpp/identity_manager.h"
+#import "services/identity/public/cpp/identity_test_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -59,13 +62,13 @@ class FakeAccountConsistencyService : public AccountConsistencyService {
scoped_refptr<content_settings::CookieSettings> cookie_settings,
GaiaCookieManagerService* gaia_cookie_manager_service,
SigninClient* signin_client,
- SigninManager* signin_manager)
+ identity::IdentityManager* identity_manager)
: AccountConsistencyService(browser_state,
account_reconcilor,
cookie_settings,
gaia_cookie_manager_service,
signin_client,
- signin_manager) {}
+ identity_manager) {}
private:
WKWebView* BuildWKWebView() override {
@@ -83,20 +86,29 @@ class MockAccountReconcilor : public AccountReconcilor {
MockAccountReconcilor(SigninClient* client)
: AccountReconcilor(
nullptr,
- nullptr,
client,
nullptr,
std::make_unique<signin::AccountReconcilorDelegate>()) {}
MOCK_METHOD1(OnReceivedManageAccountsResponse, void(signin::GAIAServiceType));
};
-// Mock GaiaCookieManagerService to catch call to ForceOnCookieChangeProcessing
-class MockGaiaCookieManagerService : public GaiaCookieManagerService {
+// Mock GaiaCookieManagerService to catch call to ForceOnCookieChangeProcessing.
+// It isn't an actual mock as it is not desirable to extend a Mock from a Fake.
+class CustomGaiaCookieManagerService : public FakeGaiaCookieManagerService {
public:
- MockGaiaCookieManagerService()
- : GaiaCookieManagerService(nullptr,
- nullptr) {}
- MOCK_METHOD0(ForceOnCookieChangeProcessing, void());
+ CustomGaiaCookieManagerService()
+ : FakeGaiaCookieManagerService(nullptr, nullptr),
+ calls_to_force_on_cookie_change_processing_(0) {}
+
+ uint8_t CallsToForceOnCookieChangeProcessing() {
+ return calls_to_force_on_cookie_change_processing_;
+ }
+
+ private:
+ void ForceOnCookieChangeProcessing() override {
+ calls_to_force_on_cookie_change_processing_++;
+ };
+ uint8_t calls_to_force_on_cookie_change_processing_;
};
// TestWebState that allows control over its policy decider.
@@ -147,7 +159,7 @@ class AccountConsistencyServiceTest : public PlatformTest {
SigninManagerBase::RegisterProfilePrefs(prefs_.registry());
web_view_load_expection_count_ = 0;
- gaia_cookie_manager_service_.reset(new MockGaiaCookieManagerService());
+ gaia_cookie_manager_service_.reset(new CustomGaiaCookieManagerService());
signin_client_.reset(new TestSigninClient(&prefs_));
account_tracker_service_.Initialize(&prefs_, base::FilePath());
token_service_.reset(new FakeProfileOAuth2TokenService(&prefs_));
@@ -155,6 +167,9 @@ class AccountConsistencyServiceTest : public PlatformTest {
new FakeSigninManager(signin_client_.get(), token_service_.get(),
&account_tracker_service_, nullptr));
signin_manager_->Initialize(nullptr);
+ identity_test_env_.reset(new identity::IdentityTestEnvironment(
+ &account_tracker_service_, token_service_.get(), signin_manager_.get(),
+ gaia_cookie_manager_service_.get()));
settings_map_ = new HostContentSettingsMap(
&prefs_, false /* incognito_profile */, false /* guest_profile */,
false /* store_last_modified */,
@@ -172,6 +187,7 @@ class AccountConsistencyServiceTest : public PlatformTest {
account_consistency_service_->Shutdown();
settings_map_->ShutdownOnUIThread();
ActiveStateManager::FromBrowserState(&browser_state_)->SetActive(false);
+ identity_test_env_.reset();
PlatformTest::TearDown();
}
@@ -201,7 +217,7 @@ class AccountConsistencyServiceTest : public PlatformTest {
account_consistency_service_.reset(new FakeAccountConsistencyService(
&browser_state_, account_reconcilor_.get(), cookie_settings_,
gaia_cookie_manager_service_.get(), signin_client_.get(),
- signin_manager_.get()));
+ identity_test_env_->identity_manager()));
}
void SignIn() {
@@ -256,13 +272,14 @@ class AccountConsistencyServiceTest : public PlatformTest {
web::TestBrowserState browser_state_;
sync_preferences::TestingPrefServiceSyncable prefs_;
TestWebState web_state_;
+ std::unique_ptr<identity::IdentityTestEnvironment> identity_test_env_;
// AccountConsistencyService being tested. Actually a
// FakeAccountConsistencyService to be able to use a mock web view.
std::unique_ptr<AccountConsistencyService> account_consistency_service_;
std::unique_ptr<TestSigninClient> signin_client_;
std::unique_ptr<FakeProfileOAuth2TokenService> token_service_;
std::unique_ptr<FakeSigninManager> signin_manager_;
- std::unique_ptr<MockGaiaCookieManagerService> gaia_cookie_manager_service_;
+ std::unique_ptr<CustomGaiaCookieManagerService> gaia_cookie_manager_service_;
std::unique_ptr<MockAccountReconcilor> account_reconcilor_;
scoped_refptr<HostContentSettingsMap> settings_map_;
scoped_refptr<content_settings::CookieSettings> cookie_settings_;
@@ -451,11 +468,11 @@ TEST_F(AccountConsistencyServiceTest, DomainsClearedOnBrowsingDataRemoved) {
prefs_.GetDictionary(AccountConsistencyService::kDomainsWithCookiePref);
EXPECT_EQ(2u, dict->size());
- EXPECT_CALL(*gaia_cookie_manager_service_, ForceOnCookieChangeProcessing())
- .Times(1);
account_consistency_service_->OnBrowsingDataRemoved();
dict =
prefs_.GetDictionary(AccountConsistencyService::kDomainsWithCookiePref);
+ EXPECT_EQ(
+ 1u, gaia_cookie_manager_service_->CallsToForceOnCookieChangeProcessing());
EXPECT_EQ(0u, dict->size());
}
@@ -468,9 +485,9 @@ TEST_F(AccountConsistencyServiceTest, DomainsClearedOnBrowsingDataRemoved2) {
AddPageLoadedExpectation(kGoogleUrl, false /* continue_navigation */);
SimulateGaiaCookieManagerServiceLogout(false);
- EXPECT_CALL(*gaia_cookie_manager_service_, ForceOnCookieChangeProcessing())
- .Times(1);
account_consistency_service_->OnBrowsingDataRemoved();
+ EXPECT_EQ(
+ 1u, gaia_cookie_manager_service_->CallsToForceOnCookieChangeProcessing());
EXPECT_TRUE(remove_cookie_callback_called_);
}
diff --git a/chromium/components/signin/ios/browser/oauth2_token_service_observer_bridge.h b/chromium/components/signin/ios/browser/oauth2_token_service_observer_bridge.h
deleted file mode 100644
index a168fac439a..00000000000
--- a/chromium/components/signin/ios/browser/oauth2_token_service_observer_bridge.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2014 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 COMPONENTS_SIGNIN_IOS_BROWSER_OAUTH2_TOKEN_SERVICE_OBSERVER_BRIDGE_H_
-#define COMPONENTS_SIGNIN_IOS_BROWSER_OAUTH2_TOKEN_SERVICE_OBSERVER_BRIDGE_H_
-
-#import <Foundation/Foundation.h>
-
-#include "base/macros.h"
-#include "google_apis/gaia/oauth2_token_service.h"
-
-@protocol OAuth2TokenServiceObserverBridgeDelegate <NSObject>
-
-@optional
-
-// Informs the delegate that a refresh token is avaible for |account_id|.
-- (void)onRefreshTokenAvailable:(const std::string&)account_id;
-
-// Informs the delegate that the refresh token was revoked for |account_id|.
-- (void)onRefreshTokenRevoked:(const std::string&)account_id;
-
-// Informs the delegate that the token service has finished loading the tokens.
-- (void)onRefreshTokensLoaded;
-
-// Informs the delegate that a batch of refresh token changes will start.
-- (void)onStartBatchChanges;
-
-// Informs the delegate that a batch of refresh token changes has ended.
-- (void)onEndBatchChanges;
-
-@end
-
-// Bridge class that listens for |OAuth2TokenService| notifications and passes
-// them to its Objective-C delegate.
-class OAuth2TokenServiceObserverBridge : public OAuth2TokenService::Observer {
- public:
- OAuth2TokenServiceObserverBridge(
- OAuth2TokenService* token_service,
- id<OAuth2TokenServiceObserverBridgeDelegate> delegate);
- ~OAuth2TokenServiceObserverBridge() override;
-
- // OAuth2TokenService::Observer
- void OnRefreshTokenAvailable(const std::string& account_id) override;
- void OnRefreshTokenRevoked(const std::string& account_id) override;
- void OnRefreshTokensLoaded() override;
- void OnStartBatchChanges() override;
- void OnEndBatchChanges() override;
-
- private:
- OAuth2TokenService* token_service_; // weak
- __weak id<OAuth2TokenServiceObserverBridgeDelegate> delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(OAuth2TokenServiceObserverBridge);
-};
-
-#endif // COMPONENTS_SIGNIN_IOS_BROWSER_OAUTH2_TOKEN_SERVICE_OBSERVER_BRIDGE_H_
diff --git a/chromium/components/signin/ios/browser/oauth2_token_service_observer_bridge.mm b/chromium/components/signin/ios/browser/oauth2_token_service_observer_bridge.mm
deleted file mode 100644
index ddaddb068d3..00000000000
--- a/chromium/components/signin/ios/browser/oauth2_token_service_observer_bridge.mm
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2014 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 "components/signin/ios/browser/oauth2_token_service_observer_bridge.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-OAuth2TokenServiceObserverBridge::OAuth2TokenServiceObserverBridge(
- OAuth2TokenService* token_service,
- id<OAuth2TokenServiceObserverBridgeDelegate> delegate)
- : token_service_(token_service),
- delegate_(delegate) {
- DCHECK(token_service_);
- token_service_->AddObserver(this);
-}
-OAuth2TokenServiceObserverBridge::~OAuth2TokenServiceObserverBridge() {
- token_service_->RemoveObserver(this);
-}
-
-void OAuth2TokenServiceObserverBridge::OnRefreshTokenAvailable(
- const std::string& account_id) {
- if ([delegate_ respondsToSelector:@selector(onRefreshTokenAvailable:)]) {
- [delegate_ onRefreshTokenAvailable:account_id];
- }
-}
-
-void OAuth2TokenServiceObserverBridge::OnRefreshTokenRevoked(
- const std::string& account_id) {
- if ([delegate_ respondsToSelector:@selector(onRefreshTokenRevoked:)]) {
- [delegate_ onRefreshTokenRevoked:account_id];
- }
-}
-void OAuth2TokenServiceObserverBridge::OnRefreshTokensLoaded() {
- if ([delegate_ respondsToSelector:@selector(onRefreshTokensLoaded)]) {
- [delegate_ onRefreshTokensLoaded];
- }
-}
-void OAuth2TokenServiceObserverBridge::OnStartBatchChanges() {
- if ([delegate_ respondsToSelector:@selector(onStartBatchChanges)]) {
- [delegate_ onStartBatchChanges];
- }
-
-}
-
-void OAuth2TokenServiceObserverBridge::OnEndBatchChanges() {
- if ([delegate_ respondsToSelector:@selector(onEndBatchChanges)]) {
- [delegate_ onEndBatchChanges];
- }
-}
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
index 1f13b5dcaab..69168d83eee 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
@@ -8,9 +8,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
-#include "base/memory/linked_ptr.h"
#include "base/threading/thread_checker.h"
-#include "components/signin/core/browser/signin_error_controller.h"
#include "google_apis/gaia/oauth2_token_service_delegate.h"
class AccountTrackerService;
@@ -22,8 +20,7 @@ class ProfileOAuth2TokenServiceIOSDelegate : public OAuth2TokenServiceDelegate {
ProfileOAuth2TokenServiceIOSDelegate(
SigninClient* client,
std::unique_ptr<ProfileOAuth2TokenServiceIOSProvider> provider,
- AccountTrackerService* account_tracker_service,
- SigninErrorController* signin_error_controller);
+ AccountTrackerService* account_tracker_service);
~ProfileOAuth2TokenServiceIOSDelegate() override;
OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
@@ -78,29 +75,13 @@ class ProfileOAuth2TokenServiceIOSDelegate : public OAuth2TokenServiceDelegate {
FRIEND_TEST_ALL_PREFIXES(ProfileOAuth2TokenServiceIOSDelegateTest,
LoadRevokeCredentialsClearsExcludedAccounts);
- class AccountStatus : public SigninErrorController::AuthStatusProvider {
- public:
- AccountStatus(SigninErrorController* signin_error_controller,
- const std::string& account_id);
- ~AccountStatus() override;
-
- void SetLastAuthError(const GoogleServiceAuthError& error);
-
- // SigninErrorController::AuthStatusProvider implementation.
- std::string GetAccountId() const override;
- GoogleServiceAuthError GetAuthStatus() const override;
-
- private:
- SigninErrorController* signin_error_controller_;
- std::string account_id_;
- GoogleServiceAuthError last_auth_error_;
-
- DISALLOW_COPY_AND_ASSIGN(AccountStatus);
+ struct AccountStatus {
+ GoogleServiceAuthError last_auth_error;
};
// Maps the |account_id| of accounts known to ProfileOAuth2TokenService
// to information about the account.
- typedef std::map<std::string, linked_ptr<AccountStatus>> AccountStatusMap;
+ typedef std::map<std::string, AccountStatus> AccountStatusMap;
// Clears exclude secondary accounts preferences.
void ClearExcludedSecondaryAccounts();
@@ -121,9 +102,6 @@ class ProfileOAuth2TokenServiceIOSDelegate : public OAuth2TokenServiceDelegate {
std::unique_ptr<ProfileOAuth2TokenServiceIOSProvider> provider_;
AccountTrackerService* account_tracker_service_;
- // The error controller with which this instance was initialized, or NULL.
- SigninErrorController* signin_error_controller_;
-
DISALLOW_COPY_AND_ASSIGN(ProfileOAuth2TokenServiceIOSDelegate);
};
#endif // COMPONENTS_SIGNIN_IOS_BROWSER_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_DELEGATE_H_
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
index c27f49c70fa..ad6e03de3a7 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
@@ -147,50 +147,16 @@ void SSOAccessTokenFetcher::OnAccessTokenResponse(NSString* token,
} // namespace
-ProfileOAuth2TokenServiceIOSDelegate::AccountStatus::AccountStatus(
- SigninErrorController* signin_error_controller,
- const std::string& account_id)
- : signin_error_controller_(signin_error_controller),
- account_id_(account_id),
- last_auth_error_(GoogleServiceAuthError::NONE) {
- DCHECK(signin_error_controller_);
- DCHECK(!account_id_.empty());
- signin_error_controller_->AddProvider(this);
-}
-
-ProfileOAuth2TokenServiceIOSDelegate::AccountStatus::~AccountStatus() {
- signin_error_controller_->RemoveProvider(this);
-}
-
-void ProfileOAuth2TokenServiceIOSDelegate::AccountStatus::SetLastAuthError(
- const GoogleServiceAuthError& error) {
- last_auth_error_ = error;
- signin_error_controller_->AuthStatusChanged();
-}
-
-std::string ProfileOAuth2TokenServiceIOSDelegate::AccountStatus::GetAccountId()
- const {
- return account_id_;
-}
-
-GoogleServiceAuthError
-ProfileOAuth2TokenServiceIOSDelegate::AccountStatus::GetAuthStatus() const {
- return last_auth_error_;
-}
-
ProfileOAuth2TokenServiceIOSDelegate::ProfileOAuth2TokenServiceIOSDelegate(
SigninClient* client,
std::unique_ptr<ProfileOAuth2TokenServiceIOSProvider> provider,
- AccountTrackerService* account_tracker_service,
- SigninErrorController* signin_error_controller)
+ AccountTrackerService* account_tracker_service)
: client_(client),
provider_(std::move(provider)),
- account_tracker_service_(account_tracker_service),
- signin_error_controller_(signin_error_controller) {
+ account_tracker_service_(account_tracker_service) {
DCHECK(client_);
DCHECK(provider_);
DCHECK(account_tracker_service_);
- DCHECK(signin_error_controller_);
}
ProfileOAuth2TokenServiceIOSDelegate::~ProfileOAuth2TokenServiceIOSDelegate() {
@@ -333,7 +299,7 @@ GoogleServiceAuthError ProfileOAuth2TokenServiceIOSDelegate::GetAuthError(
const std::string& account_id) const {
auto it = accounts_.find(account_id);
return (it == accounts_.end()) ? GoogleServiceAuthError::AuthErrorNone()
- : it->second->GetAuthStatus();
+ : it->second.last_auth_error;
}
void ProfileOAuth2TokenServiceIOSDelegate::UpdateAuthError(
@@ -352,9 +318,9 @@ void ProfileOAuth2TokenServiceIOSDelegate::UpdateAuthError(
return;
}
- AccountStatus* status = accounts_[account_id].get();
- if (error.state() != status->GetAuthStatus().state()) {
- status->SetLastAuthError(error);
+ AccountStatus* status = &accounts_[account_id];
+ if (error.state() != status->last_auth_error.state()) {
+ status->last_auth_error = error;
FireAuthErrorChanged(account_id, error);
}
}
@@ -370,21 +336,16 @@ void ProfileOAuth2TokenServiceIOSDelegate::AddOrUpdateAccount(
DCHECK(!account_tracker_service_->GetAccountInfo(account_id).email.empty());
bool account_present = accounts_.count(account_id) > 0;
- if (account_present &&
- accounts_[account_id]->GetAuthStatus().state() ==
- GoogleServiceAuthError::NONE) {
+ if (account_present && accounts_[account_id].last_auth_error.state() ==
+ GoogleServiceAuthError::NONE) {
// No need to update the account if it is already a known account and if
// there is no auth error.
return;
}
- if (!account_present) {
- accounts_[account_id].reset(
- new AccountStatus(signin_error_controller_, account_id));
- FireAuthErrorChanged(account_id, accounts_[account_id]->GetAuthStatus());
- }
-
- UpdateAuthError(account_id, GoogleServiceAuthError::AuthErrorNone());
+ accounts_[account_id].last_auth_error =
+ GoogleServiceAuthError::AuthErrorNone();
+ FireAuthErrorChanged(account_id, GoogleServiceAuthError::AuthErrorNone());
FireRefreshTokenAvailable(account_id);
}
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
index 6af23b48139..aec0b1cc31e 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
@@ -11,7 +11,6 @@
#include "components/prefs/testing_pref_service.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_error_controller.h"
#include "components/signin/core/browser/signin_pref_names.h"
#include "components/signin/core/browser/test_signin_client.h"
#include "components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h"
@@ -30,29 +29,21 @@ typedef ProfileOAuth2TokenServiceIOSProvider::AccountInfo ProviderAccount;
class ProfileOAuth2TokenServiceIOSDelegateTest
: public testing::Test,
public OAuth2AccessTokenConsumer,
- public OAuth2TokenService::Observer,
- public SigninErrorController::Observer {
+ public OAuth2TokenService::Observer {
public:
ProfileOAuth2TokenServiceIOSDelegateTest()
: factory_(NULL),
client_(&prefs_),
- signin_error_controller_(
- SigninErrorController::AccountMode::ANY_ACCOUNT),
token_available_count_(0),
token_revoked_count_(0),
tokens_loaded_count_(0),
access_token_success_(0),
access_token_failure_(0),
- error_changed_count_(0),
auth_error_changed_count_(0),
last_access_token_error_(GoogleServiceAuthError::NONE) {}
void SetUp() override {
- prefs_.registry()->RegisterListPref(
- AccountTrackerService::kAccountInfoPref);
- prefs_.registry()->RegisterIntegerPref(
- prefs::kAccountIdMigrationState,
- AccountTrackerService::MIGRATION_NOT_STARTED);
+ AccountTrackerService::RegisterPrefs(prefs_.registry());
account_tracker_.Initialize(&prefs_, base::FilePath());
prefs_.registry()->RegisterBooleanPref(
@@ -64,14 +55,11 @@ class ProfileOAuth2TokenServiceIOSDelegateTest
factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_revoke_url(), "",
net::HTTP_OK, net::URLRequestStatus::SUCCESS);
oauth2_delegate_.reset(new ProfileOAuth2TokenServiceIOSDelegate(
- &client_, base::WrapUnique(fake_provider_), &account_tracker_,
- &signin_error_controller_));
+ &client_, base::WrapUnique(fake_provider_), &account_tracker_));
oauth2_delegate_->AddObserver(this);
- signin_error_controller_.AddObserver(this);
}
void TearDown() override {
- signin_error_controller_.RemoveObserver(this);
oauth2_delegate_->RemoveObserver(this);
oauth2_delegate_->Shutdown();
}
@@ -100,16 +88,12 @@ class ProfileOAuth2TokenServiceIOSDelegateTest
++auth_error_changed_count_;
}
- // SigninErrorController::Observer implementation.
- void OnErrorChanged() override { ++error_changed_count_; }
-
void ResetObserverCounts() {
token_available_count_ = 0;
token_revoked_count_ = 0;
tokens_loaded_count_ = 0;
token_available_count_ = 0;
access_token_failure_ = 0;
- error_changed_count_ = 0;
auth_error_changed_count_ = 0;
}
@@ -124,7 +108,6 @@ class ProfileOAuth2TokenServiceIOSDelegateTest
TestingPrefServiceSimple prefs_;
TestSigninClient client_;
AccountTrackerService account_tracker_;
- SigninErrorController signin_error_controller_;
FakeProfileOAuth2TokenServiceIOSProvider* fake_provider_;
std::unique_ptr<ProfileOAuth2TokenServiceIOSDelegate> oauth2_delegate_;
TestingOAuth2TokenServiceConsumer consumer_;
@@ -133,7 +116,6 @@ class ProfileOAuth2TokenServiceIOSDelegateTest
int tokens_loaded_count_;
int access_token_success_;
int access_token_failure_;
- int error_changed_count_;
int auth_error_changed_count_;
GoogleServiceAuthError last_access_token_error_;
};
@@ -311,13 +293,11 @@ TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
oauth2_delegate_->UpdateAuthError(GetAccountId(account1), error);
EXPECT_EQ(error, oauth2_delegate_->GetAuthError("gaia_1"));
EXPECT_EQ(1, auth_error_changed_count_);
- EXPECT_EQ(1, error_changed_count_);
oauth2_delegate_->RevokeAllCredentials();
ResetObserverCounts();
oauth2_delegate_->UpdateAuthError(GetAccountId(account1), error);
EXPECT_EQ(0, auth_error_changed_count_);
- EXPECT_EQ(0, error_changed_count_);
}
TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, GetAuthError) {