Change undefined behavior of chrome.identity.onSigninChanged event
The chrome.identity.onSigninChanged extension API event is defined
as follows:
"Fired when signin state changes for an account on the user's profile."
(https://developer.chrome.com/apps/identity#event-onSignInChanged)
The current browser-side implementation uses gaia::AccountTracker,
which ignores events for secondary accounts if there is no primary
account (i.e., syncing account) present. Thus, this browser-side
implementation also fires events for secondary accounts only if there is
a primary account present.
However:
(1) This behavior is not defined in the documented semantics above
(2) In practice, this case has historically never been encountered by
end users, as it has been impossible in desktop Chrome to have a
secondary account without a primary account present.
This CL changes this undocumented behavior, so that events for
secondary events will fire regardless of whether a primary account is
present. Post-project DICE, it will be possible for this case to be
encountered by end users. In that world, it will actually be more
sensible for events to fire for secondary accounts regardless of
whether or not the user has designated a syncing account.
The CL implements this change by porting IdentityAPI away from using
gaia::AccountTracker to observing ProfileOAuth2TokenService and
AccountTrackerService directly. By doing so, IdentityAPI observes
(and fires events for) signin change events for secondary accounts
regardless of whether a primary account is present.
This change has a side benefit in removing usage of the AccountTracker
class, which is deprecated with an eye toward complete removal
(see details in crbug.com/729590). It will be followed up by a
conversion of this code to use the Identity Service client library.
To test, install a Chrome extension with the identity permissions in
its manifest. Go to chrome://extensions, enable developer mode, and
inspect the background page of the above app. At the JS console that
that brings up, execute:
chrome.identity.onSignInChanged.addListener((account, signed_in) => {console.log(account.id + " " + signed_in);} )
Sign out of the browser. Verify that you receive a callback at the console
with a value of false.
Sign back in. Verify that you receive another callback at the console for
the same account ID with a value of true.
Bug: 729589, 729542, 769700
Change-Id: I99dd48d34b380067ac34a2207effd9d3279191fd
Reviewed-on: https://chromium-review.googlesource.com/596368
Commit-Queue: Colin Blundell <[email protected]>
Reviewed-by: Mihai Sardarescu <[email protected]>
Cr-Commit-Position: refs/heads/master@{#545081}
diff --git a/chrome/browser/extensions/api/identity/identity_api.h b/chrome/browser/extensions/api/identity/identity_api.h
index 8f86f57..5fc41ec 100644
--- a/chrome/browser/extensions/api/identity/identity_api.h
+++ b/chrome/browser/extensions/api/identity/identity_api.h
@@ -27,10 +27,9 @@
#include "chrome/browser/extensions/api/identity/identity_remove_cached_auth_token_function.h"
#include "chrome/browser/extensions/api/identity/web_auth_flow.h"
#include "chrome/browser/extensions/chrome_extension_function.h"
-#include "components/signin/core/browser/profile_identity_provider.h"
+#include "components/signin/core/browser/account_tracker_service.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/event_router.h"
-#include "google_apis/gaia/account_tracker.h"
#include "google_apis/gaia/oauth2_mint_token_flow.h"
#include "google_apis/gaia/oauth2_token_service.h"
@@ -38,6 +37,8 @@
class BrowserContext;
}
+class Profile;
+
namespace extensions {
class IdentityTokenCacheValue {
@@ -72,7 +73,8 @@
};
class IdentityAPI : public BrowserContextKeyedAPI,
- public gaia::AccountTracker::Observer {
+ public AccountTrackerService::Observer,
+ public OAuth2TokenService::Observer {
public:
typedef std::map<ExtensionTokenKey, IdentityTokenCacheValue> CachedTokens;
@@ -92,24 +94,15 @@
const CachedTokens& GetAllCachedTokens();
- // BrowserContextKeyedAPI implementation.
+ // BrowserContextKeyedAPI:
void Shutdown() override;
static BrowserContextKeyedAPIFactory<IdentityAPI>* GetFactoryInstance();
- // gaia::AccountTracker::Observer implementation:
- void OnAccountSignInChanged(const gaia::AccountIds& ids,
- bool is_signed_in) override;
-
std::unique_ptr<base::CallbackList<void()>::Subscription>
RegisterOnShutdownCallback(const base::Closure& cb) {
return on_shutdown_callback_list_.Add(cb);
}
- // TODO(blundell): Eliminate this method once this class is no longer using
- // AccountTracker.
- // Makes |account_tracker_| aware of this account.
- void SetAccountStateForTesting(const std::string& account_id, bool signed_in);
-
// Callback that is used in testing contexts to test the implementation of
// the chrome.identity.onSignInChanged event. Note that the passed-in Event is
// valid only for the duration of the callback.
@@ -122,15 +115,31 @@
private:
friend class BrowserContextKeyedAPIFactory<IdentityAPI>;
- // BrowserContextKeyedAPI implementation.
+ // BrowserContextKeyedAPI:
static const char* service_name() { return "IdentityAPI"; }
static const bool kServiceIsNULLWhileTesting = true;
- content::BrowserContext* browser_context_;
+ // OAuth2TokenService::Observer:
+ void OnRefreshTokenAvailable(const std::string& account_id) override;
+
+ // AccountTrackerService::Observer:
+ // NOTE: This class listens for signout events via this callback (which itself
+ // is triggered by O2TS::OnRefreshTokenRevoked()) rather than directly via
+ // OnRefreshTokenRevoked() in order to obtain the Gaia ID of the signed-out
+ // account, which is needed to send as input to the
+ // chrome.identity.onSigninChanged event. That Gaia ID is not guaranteed to be
+ // available from O2TS::OnRefreshTokenRevoked().
+ // TODO(blundell): Eliminate this kludge by porting this class to interact
+ // with IdentityManager.
+ void OnAccountRemoved(const AccountInfo& info) override;
+
+ // Fires the chrome.identity.onSignInChanged event.
+ void FireOnAccountSignInChanged(const std::string& gaia_id,
+ bool is_signed_in);
+
+ Profile* profile_;
IdentityMintRequestQueue mint_queue_;
CachedTokens token_cache_;
- ProfileIdentityProvider profile_identity_provider_;
- gaia::AccountTracker account_tracker_;
OnSignInChangedCallback on_signin_changed_callback_for_testing_;