Commit 21a49480 authored by Mihai Sardarescu's avatar Mihai Sardarescu Committed by Commit Bot

[signin] Add refresh token events to signin-internals page

This CL adds information about token events in the chrome://signin-internals
page. This is needed to allow developers to debug issues when the Google
auth state if changed by the browser (either due to Mirror or Dice).

A follow-up CL will add the source for the refresh token events.

Bug: 896182

Change-Id: Ie70e3e647947aa771572ed47992e2d0c59bea361
Reviewed-on: https://chromium-review.googlesource.com/c/1286460
Commit-Queue: Mihai Sardarescu <msarda@chromium.org>
Reviewed-by: default avatarDavid Roger <droger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#601129}
parent 6f02e862
......@@ -35,6 +35,10 @@ using namespace signin_internals_util;
namespace {
// The maximum number of the refresh token events. Only the last
// |kMaxRefreshTokenListSize| events are kept in memory.
const size_t kMaxRefreshTokenListSize = 50;
std::string GetTimeStr(base::Time time) {
return base::UTF16ToUTF8(base::TimeFormatShortDateAndTime(time));
}
......@@ -290,6 +294,7 @@ void AboutSigninInternals::Initialize(SigninClient* client) {
signin_error_controller_->AddObserver(this);
signin_manager_->AddObserver(this);
signin_manager_->AddSigninDiagnosticsObserver(this);
token_service_->AddObserver(this);
token_service_->AddDiagnosticsObserver(this);
cookie_manager_service_->AddObserver(this);
}
......@@ -298,6 +303,7 @@ void AboutSigninInternals::Shutdown() {
signin_error_controller_->RemoveObserver(this);
signin_manager_->RemoveObserver(this);
signin_manager_->RemoveSigninDiagnosticsObserver(this);
token_service_->RemoveObserver(this);
token_service_->RemoveDiagnosticsObserver(this);
cookie_manager_service_->RemoveObserver(this);
}
......@@ -356,7 +362,33 @@ void AboutSigninInternals::OnFetchAccessTokenComplete(
NotifyObservers();
}
void AboutSigninInternals::OnRefreshTokenAvailable(
const std::string& account_id) {
RefreshTokenEvent event;
event.account_id = account_id;
event.type = AboutSigninInternals::RefreshTokenEventType::kUpdateToRegular;
GoogleServiceAuthError token_error = token_service_->GetAuthError(account_id);
if (token_error == GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
GoogleServiceAuthError::InvalidGaiaCredentialsReason::
CREDENTIALS_REJECTED_BY_CLIENT)) {
event.type = AboutSigninInternals::RefreshTokenEventType::kUpdateToInvalid;
}
signin_status_.AddRefreshTokenEvent(event);
}
void AboutSigninInternals::OnRefreshTokenRevoked(
const std::string& account_id) {
RefreshTokenEvent event;
event.account_id = account_id;
event.type = AboutSigninInternals::RefreshTokenEventType::kRevokeRegular;
signin_status_.AddRefreshTokenEvent(event);
}
void AboutSigninInternals::OnRefreshTokensLoaded() {
RefreshTokenEvent event;
event.account_id = "All accounts";
event.type = AboutSigninInternals::RefreshTokenEventType::kAllTokensLoaded;
signin_status_.AddRefreshTokenEvent(event);
NotifyObservers();
}
......@@ -494,6 +526,22 @@ AboutSigninInternals::TokenInfo::ToValue() const {
return token_info;
}
AboutSigninInternals::RefreshTokenEvent::RefreshTokenEvent()
: timestamp(Time::Now()){};
std::string AboutSigninInternals::RefreshTokenEvent::GetTypeAsString() const {
switch (type) {
case AboutSigninInternals::RefreshTokenEventType::kUpdateToRegular:
return "Updated";
case AboutSigninInternals::RefreshTokenEventType::kUpdateToInvalid:
return "Invalidated";
case AboutSigninInternals::RefreshTokenEventType::kRevokeRegular:
return "Revoked";
case AboutSigninInternals::RefreshTokenEventType::kAllTokensLoaded:
return "Loaded";
}
}
AboutSigninInternals::SigninStatus::SigninStatus()
: timed_signin_fields(TIMED_FIELDS_COUNT) {}
......@@ -510,6 +558,14 @@ AboutSigninInternals::TokenInfo* AboutSigninInternals::SigninStatus::FindToken(
return nullptr;
}
void AboutSigninInternals::SigninStatus::AddRefreshTokenEvent(
const AboutSigninInternals::RefreshTokenEvent& event) {
if (refresh_token_events.size() > kMaxRefreshTokenListSize)
refresh_token_events.pop_front();
refresh_token_events.push_back(event);
}
std::unique_ptr<base::DictionaryValue>
AboutSigninInternals::SigninStatus::ToValue(
AccountTrackerService* account_tracker,
......@@ -626,26 +682,39 @@ AboutSigninInternals::SigninStatus::ToValue(
}
signin_status->Set("token_info", std::move(token_info));
// Account info section
auto account_info = std::make_unique<base::ListValue>();
const std::vector<std::string>& accounts_in_token_service =
token_service->GetAccounts();
if (accounts_in_token_service.size() == 0) {
auto no_token_entry = std::make_unique<base::DictionaryValue>();
no_token_entry->SetString("accountId", "No token in Token Service.");
account_info->Append(std::move(no_token_entry));
} else {
for (const std::string& account_id : accounts_in_token_service) {
auto entry = std::make_unique<base::DictionaryValue>();
entry->SetString("accountId", account_id);
entry->SetBoolean("hasRefreshToken",
token_service->RefreshTokenIsAvailable(account_id));
entry->SetBoolean("hasAuthError",
token_service->RefreshTokenHasError(account_id));
account_info->Append(std::move(entry));
}
}
signin_status->Set("accountInfo", std::move(account_info));
for (const std::string& account_id : accounts_in_token_service) {
// Refresh token events section
auto refresh_token_events_value = std::make_unique<base::ListValue>();
for (const auto& event : refresh_token_events) {
auto entry = std::make_unique<base::DictionaryValue>();
entry->SetString("accountId", account_id);
entry->SetBoolean("hasRefreshToken",
token_service->RefreshTokenIsAvailable(account_id));
entry->SetBoolean("hasAuthError",
token_service->RefreshTokenHasError(account_id));
account_info->Append(std::move(entry));
entry->SetString("accountId", event.account_id);
entry->SetString("timestamp", GetTimeStr(event.timestamp));
entry->SetString("type", event.GetTypeAsString());
entry->SetString("source", event.source);
refresh_token_events_value->Append(std::move(entry));
}
signin_status->Set("refreshTokenEvents",
std::move(refresh_token_events_value));
signin_status->Set("accountInfo", std::move(account_info));
return signin_status;
}
......@@ -5,6 +5,7 @@
#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_ABOUT_SIGNIN_INTERNALS_H_
#define COMPONENTS_SIGNIN_CORE_BROWSER_ABOUT_SIGNIN_INTERNALS_H_
#include <deque>
#include <map>
#include <memory>
#include <string>
......@@ -122,6 +123,23 @@ class AboutSigninInternals
bool removed_;
};
enum class RefreshTokenEventType {
kUpdateToRegular,
kUpdateToInvalid,
kRevokeRegular,
kAllTokensLoaded,
};
struct RefreshTokenEvent {
RefreshTokenEvent();
std::string GetTypeAsString() const;
const base::Time timestamp;
std::string account_id;
RefreshTokenEventType type;
std::string source;
};
// Encapsulates both authentication and token related information. Used
// by SigninInternals to maintain information that needs to be shown in
// the about:signin-internals page.
......@@ -132,6 +150,9 @@ class AboutSigninInternals
std::map<std::string, std::vector<std::unique_ptr<TokenInfo>>>
token_info_map;
// All the events that affected the refresh tokens.
std::deque<RefreshTokenEvent> refresh_token_events;
SigninStatus();
~SigninStatus();
......@@ -139,6 +160,8 @@ class AboutSigninInternals
const std::string& consumer_id,
const OAuth2TokenService::ScopeSet& scopes);
void AddRefreshTokenEvent(const RefreshTokenEvent& event);
// Returns a dictionary with the following form:
// { "signin_info" :
// [ {"title": "Basic Information",
......@@ -186,6 +209,8 @@ class AboutSigninInternals
const OAuth2TokenService::ScopeSet& scopes) override;
// OAuth2TokenServiceDelegate::Observer implementations.
void OnRefreshTokenAvailable(const std::string& account_id) override;
void OnRefreshTokenRevoked(const std::string& account_id) override;
void OnRefreshTokensLoaded() override;
void OnEndBatchChanges() override;
......
......@@ -89,6 +89,26 @@
</table>
</div>
</div>
<div id="refresh-token-events">
<h2>Refresh token events</h2>
<div class="refresh-token-events-section">
<table class="signin-details">
<tr class="header">
<td>Timestamp</td>
<td>Accound Id</td>
<td>Event type</td>
<td>Source</td>
</tr>
<tr jsselect="refreshTokenEvents">
<td jscontent="timestamp"></td>
<td jscontent="accountId"></td>
<td jscontent="type"></td>
<td jscontent="source"></td>
</tr>
</table>
</div>
</div>
<script src="chrome://resources/js/i18n_template.js"></script>
<script src="chrome://resources/js/jstemplate_compiled.js"></script>
<script src="chrome://signin-internals/signin_internals.js"></script>
......
......@@ -169,6 +169,7 @@ function refreshSigninInfo(signinInfo) {
jstProcess(new JsEvalContext(signinInfo), $('signin-info'));
jstProcess(new JsEvalContext(signinInfo), $('token-info'));
jstProcess(new JsEvalContext(signinInfo), $('account-info'));
jstProcess(new JsEvalContext(signinInfo), $('refresh-token-events'));
}
// Replace the cookie information with the fetched values.
......
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