Commit 3e56f21b authored by mlerman@chromium.org's avatar mlerman@chromium.org

Show GAIA/cookie accounts on the signin-internals page.

BUG=326577

Review URL: https://codereview.chromium.org/421583002

Cr-Commit-Position: refs/heads/master@{#288493}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288493 0039d316-1c4b-4281-b951-d872f2087c98
parent f71582a1
......@@ -30,7 +30,8 @@ div#signin-info {
-webkit-columns: 2;
}
div#token-info {
div#token-info,
div#cookie-info {
-webkit-columns: 1;
}
......
......@@ -50,6 +50,21 @@
</table>
</div>
</div>
<div id='cookie-info'>
<h2>Accounts in Cookie Jar</h2>
<div class="cookieSection">
<table class="signin-details">
<tr class="header">
<td>Email Address</td>
<td>Validity</td>
</tr>
<tr jsselect="cookie_info">
<td jscontent="email"></td>
<td jscontent="valid"></td>
</tr>
</table>
</div>
</div>
<script src="chrome://resources/js/i18n_template.js"></script>
<script src="chrome://resources/js/i18n_process.js"></script>
<script src="chrome://resources/js/jstemplate_compiled.js"></script>
......
......@@ -112,7 +112,8 @@ Event.prototype.fire = function() {
// These are the events that will be registered.
chrome.signin.events = {
'signin_manager': [
'onSigninInfoChanged'
'onSigninInfoChanged',
'onCookieAccountsFetched'
]
};
......@@ -165,10 +166,13 @@ chrome.signin.internalsInfo = {};
// Replace the displayed values with the latest fetched ones.
function refreshSigninInfo(signinInfo) {
chrome.signin.internalsInfo = signinInfo;
var internalsInfoDiv = $('signin-info');
jstProcess(new JsEvalContext(signinInfo), internalsInfoDiv);
var tokenInfoDiv = $('token-info');
jstProcess(new JsEvalContext(signinInfo), tokenInfoDiv);
jstProcess(new JsEvalContext(signinInfo), $('signin-info'));
jstProcess(new JsEvalContext(signinInfo), $('token-info'));
}
// Replace the cookie information with the fetched values.
function updateCookieAccounts(cookieAccountsInfo) {
jstProcess(new JsEvalContext(cookieAccountsInfo), $('cookie-info'));
}
// On load, do an initial refresh and register refreshSigninInfo to be invoked
......@@ -176,9 +180,8 @@ function refreshSigninInfo(signinInfo) {
function onLoad() {
chrome.signin.getSigninInfo(refreshSigninInfo);
chrome.signin.onSigninInfoChanged.addListener(function(info) {
refreshSigninInfo(info);
});
chrome.signin.onSigninInfoChanged.addListener(refreshSigninInfo);
chrome.signin.onCookieAccountsFetched.addListener(updateCookieAccounts);
}
document.addEventListener('DOMContentLoaded', onLoad, false);
......
......@@ -40,7 +40,11 @@ const char kGoogleAccountsUrl[] = "https://accounts.google.com";
} // namespace
ChromeSigninClient::ChromeSigninClient(Profile* profile)
: profile_(profile), signin_host_id_(ChildProcessHost::kInvalidUniqueID) {}
: profile_(profile), signin_host_id_(ChildProcessHost::kInvalidUniqueID) {
callbacks_.set_removal_callback(
base::Bind(&ChromeSigninClient::UnregisterForCookieChangedNotification,
base::Unretained(this)));
}
ChromeSigninClient::~ChromeSigninClient() {
UnregisterForCookieChangedNotification();
......@@ -172,18 +176,13 @@ std::string ChromeSigninClient::GetProductVersion() {
return chrome_version.CreateVersionString();
}
void ChromeSigninClient::SetCookieChangedCallback(
scoped_ptr<SigninClient::CookieChangedCallbackList::Subscription>
ChromeSigninClient::AddCookieChangedCallback(
const CookieChangedCallback& callback) {
if (callback_.Equals(callback))
return;
// There should be only one callback active at a time.
DCHECK(callback.is_null() || callback_.is_null());
callback_ = callback;
if (!callback_.is_null())
scoped_ptr<SigninClient::CookieChangedCallbackList::Subscription>
subscription = callbacks_.Add(callback);
RegisterForCookieChangedNotification();
else
UnregisterForCookieChangedNotification();
return subscription.Pass();
}
void ChromeSigninClient::GoogleSigninSucceeded(const std::string& username,
......@@ -200,10 +199,10 @@ void ChromeSigninClient::Observe(int type,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_COOKIE_CHANGED: {
DCHECK(!callback_.is_null());
DCHECK(!callbacks_.empty());
const net::CanonicalCookie* cookie =
content::Details<ChromeCookieDetails>(details).ptr()->cookie;
callback_.Run(cookie);
callbacks_.Notify(cookie);
break;
}
default:
......@@ -213,13 +212,17 @@ void ChromeSigninClient::Observe(int type,
}
void ChromeSigninClient::RegisterForCookieChangedNotification() {
if (callbacks_.empty())
return;
content::Source<Profile> source(profile_);
DCHECK(!registrar_.IsRegistered(
this, chrome::NOTIFICATION_COOKIE_CHANGED, source));
if (!registrar_.IsRegistered(
this, chrome::NOTIFICATION_COOKIE_CHANGED, source))
registrar_.Add(this, chrome::NOTIFICATION_COOKIE_CHANGED, source);
}
void ChromeSigninClient::UnregisterForCookieChangedNotification() {
if (!callbacks_.empty())
return;
// Note that it's allowed to call this method multiple times without an
// intervening call to |RegisterForCookieChangedNotification()|.
content::Source<Profile> source(profile_);
......
......@@ -56,8 +56,8 @@ class ChromeSigninClient : public SigninClient,
// <Build Info> <OS> <Version number> (<Last change>)<channel or "-devel">
// If version information is unavailable, returns "invalid."
virtual std::string GetProductVersion() OVERRIDE;
virtual void SetCookieChangedCallback(const CookieChangedCallback& callback)
OVERRIDE;
virtual scoped_ptr<CookieChangedCallbackList::Subscription>
AddCookieChangedCallback(const CookieChangedCallback& callback) OVERRIDE;
virtual void GoogleSigninSucceeded(const std::string& username,
const std::string& password) OVERRIDE;
......@@ -73,9 +73,9 @@ class ChromeSigninClient : public SigninClient,
Profile* profile_;
content::NotificationRegistrar registrar_;
// The callback that if non-empty will be called when notifications about
// cookie changes are received.
CookieChangedCallback callback_;
// The callbacks that will be called when notifications about cookie changes
// are received.
base::CallbackList<void(const net::CanonicalCookie* cookie)> callbacks_;
// See SetSigninProcess. Tracks the currently active signin process
// by ID, if there is one.
......
......@@ -67,10 +67,10 @@ bool SignInInternalsUI::OverrideHandleWebUIMessage(
// empty in incognito mode. Alternatively, we could force about:signin to
// open in non-incognito mode always (like about:settings for ex.).
if (about_signin_internals) {
const std::string& reply_handler =
"chrome.signin.getSigninInfo.handleReply";
web_ui()->CallJavascriptFunction(
reply_handler, *about_signin_internals->GetSigninStatus());
"chrome.signin.getSigninInfo.handleReply",
*about_signin_internals->GetSigninStatus());
about_signin_internals->GetCookieAccountsAsync();
return true;
}
......@@ -80,6 +80,12 @@ bool SignInInternalsUI::OverrideHandleWebUIMessage(
void SignInInternalsUI::OnSigninStateChanged(
scoped_ptr<base::DictionaryValue> info) {
const std::string& event_handler = "chrome.signin.onSigninInfoChanged.fire";
web_ui()->CallJavascriptFunction(event_handler, *info);
web_ui()->CallJavascriptFunction(
"chrome.signin.onSigninInfoChanged.fire", *info);
}
void SignInInternalsUI::OnCookieAccountsFetched(
scoped_ptr<base::DictionaryValue> info) {
web_ui()->CallJavascriptFunction(
"chrome.signin.onCookieAccountsFetched.fire", *info);
}
......@@ -29,6 +29,10 @@ class SignInInternalsUI : public content::WebUIController,
virtual void OnSigninStateChanged(
scoped_ptr<base::DictionaryValue> info) OVERRIDE;
// Notification that the cookie accounts are ready to be displayed.
virtual void OnCookieAccountsFetched(
scoped_ptr<base::DictionaryValue> info) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(SignInInternalsUI);
};
......
......@@ -18,7 +18,11 @@
#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/core/common/profile_management_switches.h"
#include "components/signin/core/common/signin_switches.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/gaia_urls.h"
#include "net/cookies/canonical_cookie.h"
using base::Time;
using namespace signin_internals_util;
......@@ -51,6 +55,15 @@ void AddSectionEntry(base::ListValue* section_list,
section_list->Append(entry.release());
}
void AddCookieEntry(base::ListValue* accounts_list,
const std::string& field_email,
const std::string& field_valid) {
scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue());
entry->SetString("email", field_email);
entry->SetString("valid", field_valid);
accounts_list->Append(entry.release());
}
std::string SigninStatusFieldToLabel(UntimedSigninStatusField field) {
switch (field) {
case USERNAME:
......@@ -195,11 +208,15 @@ void AboutSigninInternals::Initialize(SigninClient* client) {
signin_manager_->AddSigninDiagnosticsObserver(this);
token_service_->AddDiagnosticsObserver(this);
cookie_changed_subscription_ = client_->AddCookieChangedCallback(
base::Bind(&AboutSigninInternals::OnCookieChanged,
base::Unretained(this)));
}
void AboutSigninInternals::Shutdown() {
signin_manager_->RemoveSigninDiagnosticsObserver(this);
token_service_->RemoveDiagnosticsObserver(this);
cookie_changed_subscription_.reset();
}
void AboutSigninInternals::NotifyObservers() {
......@@ -267,6 +284,65 @@ void AboutSigninInternals::OnAuthenticationResultReceived(std::string status) {
NotifySigninValueChanged(AUTHENTICATION_RESULT_RECEIVED, status);
}
void AboutSigninInternals::OnCookieChanged(
const net::CanonicalCookie* cookie) {
if (cookie->Name() == "LSID" &&
cookie->Domain() == GaiaUrls::GetInstance()->gaia_url().host() &&
cookie->IsSecure() &&
cookie->IsHttpOnly()) {
GetCookieAccountsAsync();
}
}
void AboutSigninInternals::GetCookieAccountsAsync() {
if (!gaia_fetcher_) {
// There is no list account request in flight.
gaia_fetcher_.reset(new GaiaAuthFetcher(
this, GaiaConstants::kChromeSource, client_->GetURLRequestContext()));
gaia_fetcher_->StartListAccounts();
}
}
void AboutSigninInternals::OnListAccountsSuccess(const std::string& data) {
gaia_fetcher_.reset();
// Get account information from response data.
std::vector<std::pair<std::string, bool> > gaia_accounts;
bool valid_json = gaia::ParseListAccountsData(data, &gaia_accounts);
if (!valid_json) {
VLOG(1) << "AboutSigninInternals::OnListAccountsSuccess: parsing error";
} else {
OnListAccountsComplete(gaia_accounts);
}
}
void AboutSigninInternals::OnListAccountsFailure(
const GoogleServiceAuthError& error) {
gaia_fetcher_.reset();
VLOG(1) << "AboutSigninInternals::OnListAccountsFailure:" << error.ToString();
}
void AboutSigninInternals::OnListAccountsComplete(
std::vector<std::pair<std::string, bool> >& gaia_accounts) {
scoped_ptr<base::DictionaryValue> signin_status(new base::DictionaryValue());
base::ListValue* cookie_info = new base::ListValue();
signin_status->Set("cookie_info", cookie_info);
for (size_t i = 0; i < gaia_accounts.size(); ++i) {
AddCookieEntry(cookie_info,
gaia_accounts[i].first,
gaia_accounts[i].second ? "Valid" : "Invalid");
}
if (gaia_accounts.size() == 0)
AddCookieEntry(cookie_info, "No Accounts Present.", "");
// Update the observers that the cookie's accounts are updated.
FOR_EACH_OBSERVER(AboutSigninInternals::Observer,
signin_observers_,
OnCookieAccountsFetched(signin_status.Pass()));
}
AboutSigninInternals::TokenInfo::TokenInfo(
const std::string& consumer_id,
const OAuth2TokenService::ScopeSet& scopes)
......
......@@ -12,10 +12,13 @@
#include "base/observer_list.h"
#include "base/values.h"
#include "components/keyed_service/core/keyed_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 "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/oauth2_token_service.h"
class GaiaAuthFetcher;
class ProfileOAuth2TokenService;
class SigninClient;
class SigninManagerBase;
......@@ -29,7 +32,8 @@ typedef std::pair<std::string, std::string> TimedSigninStatusValue;
class AboutSigninInternals
: public KeyedService,
public signin_internals_util::SigninDiagnosticsObserver,
public OAuth2TokenService::DiagnosticsObserver {
public OAuth2TokenService::DiagnosticsObserver,
public GaiaAuthConsumer {
public:
class Observer {
public:
......@@ -37,6 +41,10 @@ class AboutSigninInternals
// in the comments for GetSigninStatus() below.
virtual void OnSigninStateChanged(
scoped_ptr<base::DictionaryValue> info) = 0;
// Notification that the cookie accounts are ready to be displayed.
virtual void OnCookieAccountsFetched(
scoped_ptr<base::DictionaryValue> info) = 0;
};
AboutSigninInternals(ProfileOAuth2TokenService* token_service,
......@@ -81,6 +89,10 @@ class AboutSigninInternals
// }
scoped_ptr<base::DictionaryValue> GetSigninStatus();
// Triggers a ListAccounts call to acquire a list of the email addresses
// corresponding to the cookies residing on the current cookie jar.
void GetCookieAccountsAsync();
// OAuth2TokenService::DiagnosticsObserver implementations.
virtual void OnAccessTokenRequested(
const std::string& account_id,
......@@ -161,6 +173,21 @@ class AboutSigninInternals
void NotifyObservers();
// Overriden from GaiaAuthConsumer.
virtual void OnListAccountsSuccess(const std::string& data) OVERRIDE;
virtual void OnListAccountsFailure(const GoogleServiceAuthError& error)
OVERRIDE;
// Callback for ListAccounts. Once the email addresses are fetched from GAIA,
// they are pushed to the signin_internals_ui.
void OnListAccountsComplete(
std::vector<std::pair<std::string, bool> >& gaia_accounts);
// Called when a cookie changes. If the cookie relates to a GAIA LSID cookie,
// then we call ListAccounts and update the UI element.
void OnCookieChanged(const net::CanonicalCookie* cookie);
// Weak pointer to the token service.
ProfileOAuth2TokenService* token_service_;
......@@ -170,12 +197,18 @@ class AboutSigninInternals
// Weak pointer to the client.
SigninClient* client_;
// Fetcher for information about accounts in the cookie jar from GAIA.
scoped_ptr<GaiaAuthFetcher> gaia_fetcher_;
// Encapsulates the actual signin and token related values.
// Most of the values are mirrored in the prefs for persistence.
SigninStatus signin_status_;
ObserverList<Observer> signin_observers_;
scoped_ptr<SigninClient::CookieChangedCallbackList::Subscription>
cookie_changed_subscription_;
DISALLOW_COPY_AND_ASSIGN(AboutSigninInternals);
};
......
......@@ -275,12 +275,12 @@ void AccountReconcilor::RegisterForCookieChanges() {
// First clear any existing registration to avoid DCHECKs that can otherwise
// go off in some embedders on reauth (e.g., ChromeSigninClient).
UnregisterForCookieChanges();
client_->SetCookieChangedCallback(
cookie_changed_subscription_ = client_->AddCookieChangedCallback(
base::Bind(&AccountReconcilor::OnCookieChanged, base::Unretained(this)));
}
void AccountReconcilor::UnregisterForCookieChanges() {
client_->SetCookieChangedCallback(SigninClient::CookieChangedCallback());
cookie_changed_subscription_.reset();
}
void AccountReconcilor::RegisterWithSigninManager() {
......
......@@ -17,6 +17,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/signin/core/browser/signin_client.h"
#include "components/signin/core/browser/signin_manager.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/google_service_auth_error.h"
......@@ -259,6 +260,9 @@ class AccountReconcilor : public KeyedService,
std::deque<GetAccountsFromCookieCallback> get_gaia_accounts_callbacks_;
scoped_ptr<SigninClient::CookieChangedCallbackList::Subscription>
cookie_changed_subscription_;
DISALLOW_COPY_AND_ASSIGN(AccountReconcilor);
};
......
......@@ -6,6 +6,7 @@
#define COMPONENTS_SIGNIN_CORE_BROWSER_SIGNIN_CLIENT_H_
#include "base/callback.h"
#include "base/callback_list.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/signin/core/browser/webdata/token_web_data.h"
......@@ -33,6 +34,9 @@ class SigninClient : public KeyedService {
typedef base::Callback<void(const net::CanonicalCookie* cookie)>
CookieChangedCallback;
typedef base::CallbackList<void(const net::CanonicalCookie* cookie)>
CookieChangedCallbackList;
virtual ~SigninClient() {}
// Gets the preferences associated with the client.
......@@ -65,13 +69,12 @@ class SigninClient : public KeyedService {
// Signin component is being used.
virtual std::string GetProductVersion() = 0;
// Sets the callback that should be called when a cookie changes. The
// callback will be called only if it is not empty.
// Adds or removes a callback that should be called when a cookie changes.
// TODO(blundell): Eliminate this interface in favor of having core signin
// code observe cookie changes once //chrome/browser/net has been
// componentized.
virtual void SetCookieChangedCallback(
const CookieChangedCallback& callback) = 0;
virtual scoped_ptr<CookieChangedCallbackList::Subscription>
AddCookieChangedCallback(const CookieChangedCallback& callback) = 0;
// Called when Google signin has succeeded.
virtual void GoogleSigninSucceeded(const std::string& username,
......
......@@ -74,8 +74,11 @@ bool TestSigninClient::ShouldMergeSigninCredentialsIntoCookieJar() {
return true;
}
void TestSigninClient::SetCookieChangedCallback(
const CookieChangedCallback& callback) {}
scoped_ptr<SigninClient::CookieChangedCallbackList::Subscription>
TestSigninClient::AddCookieChangedCallback(
const SigninClient::CookieChangedCallback& callback) {
return cookie_callbacks_.Add(callback);
}
#if defined(OS_IOS)
ios::ProfileOAuth2TokenServiceIOSProvider* TestSigninClient::GetIOSProvider() {
......
......@@ -61,8 +61,8 @@ class TestSigninClient : public SigninClient {
virtual bool ShouldMergeSigninCredentialsIntoCookieJar() OVERRIDE;
// Does nothing.
virtual void SetCookieChangedCallback(const CookieChangedCallback& callback)
OVERRIDE;
virtual scoped_ptr<CookieChangedCallbackList::Subscription>
AddCookieChangedCallback(const CookieChangedCallback& callback) OVERRIDE;
#if defined(OS_IOS)
ios::FakeProfileOAuth2TokenServiceIOSProvider* GetIOSProviderAsFake();
......@@ -82,6 +82,7 @@ class TestSigninClient : public SigninClient {
scoped_refptr<net::TestURLRequestContextGetter> request_context_;
scoped_refptr<TokenWebData> database_;
int signin_host_id_;
CookieChangedCallbackList cookie_callbacks_;
PrefService* pref_service_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment