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; ...@@ -35,6 +35,10 @@ using namespace signin_internals_util;
namespace { 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) { std::string GetTimeStr(base::Time time) {
return base::UTF16ToUTF8(base::TimeFormatShortDateAndTime(time)); return base::UTF16ToUTF8(base::TimeFormatShortDateAndTime(time));
} }
...@@ -290,6 +294,7 @@ void AboutSigninInternals::Initialize(SigninClient* client) { ...@@ -290,6 +294,7 @@ void AboutSigninInternals::Initialize(SigninClient* client) {
signin_error_controller_->AddObserver(this); signin_error_controller_->AddObserver(this);
signin_manager_->AddObserver(this); signin_manager_->AddObserver(this);
signin_manager_->AddSigninDiagnosticsObserver(this); signin_manager_->AddSigninDiagnosticsObserver(this);
token_service_->AddObserver(this);
token_service_->AddDiagnosticsObserver(this); token_service_->AddDiagnosticsObserver(this);
cookie_manager_service_->AddObserver(this); cookie_manager_service_->AddObserver(this);
} }
...@@ -298,6 +303,7 @@ void AboutSigninInternals::Shutdown() { ...@@ -298,6 +303,7 @@ void AboutSigninInternals::Shutdown() {
signin_error_controller_->RemoveObserver(this); signin_error_controller_->RemoveObserver(this);
signin_manager_->RemoveObserver(this); signin_manager_->RemoveObserver(this);
signin_manager_->RemoveSigninDiagnosticsObserver(this); signin_manager_->RemoveSigninDiagnosticsObserver(this);
token_service_->RemoveObserver(this);
token_service_->RemoveDiagnosticsObserver(this); token_service_->RemoveDiagnosticsObserver(this);
cookie_manager_service_->RemoveObserver(this); cookie_manager_service_->RemoveObserver(this);
} }
...@@ -356,7 +362,33 @@ void AboutSigninInternals::OnFetchAccessTokenComplete( ...@@ -356,7 +362,33 @@ void AboutSigninInternals::OnFetchAccessTokenComplete(
NotifyObservers(); 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() { void AboutSigninInternals::OnRefreshTokensLoaded() {
RefreshTokenEvent event;
event.account_id = "All accounts";
event.type = AboutSigninInternals::RefreshTokenEventType::kAllTokensLoaded;
signin_status_.AddRefreshTokenEvent(event);
NotifyObservers(); NotifyObservers();
} }
...@@ -494,6 +526,22 @@ AboutSigninInternals::TokenInfo::ToValue() const { ...@@ -494,6 +526,22 @@ AboutSigninInternals::TokenInfo::ToValue() const {
return token_info; 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() AboutSigninInternals::SigninStatus::SigninStatus()
: timed_signin_fields(TIMED_FIELDS_COUNT) {} : timed_signin_fields(TIMED_FIELDS_COUNT) {}
...@@ -510,6 +558,14 @@ AboutSigninInternals::TokenInfo* AboutSigninInternals::SigninStatus::FindToken( ...@@ -510,6 +558,14 @@ AboutSigninInternals::TokenInfo* AboutSigninInternals::SigninStatus::FindToken(
return nullptr; 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> std::unique_ptr<base::DictionaryValue>
AboutSigninInternals::SigninStatus::ToValue( AboutSigninInternals::SigninStatus::ToValue(
AccountTrackerService* account_tracker, AccountTrackerService* account_tracker,
...@@ -626,26 +682,39 @@ AboutSigninInternals::SigninStatus::ToValue( ...@@ -626,26 +682,39 @@ AboutSigninInternals::SigninStatus::ToValue(
} }
signin_status->Set("token_info", std::move(token_info)); signin_status->Set("token_info", std::move(token_info));
// Account info section
auto account_info = std::make_unique<base::ListValue>(); auto account_info = std::make_unique<base::ListValue>();
const std::vector<std::string>& accounts_in_token_service = const std::vector<std::string>& accounts_in_token_service =
token_service->GetAccounts(); token_service->GetAccounts();
if (accounts_in_token_service.size() == 0) { if (accounts_in_token_service.size() == 0) {
auto no_token_entry = std::make_unique<base::DictionaryValue>(); auto no_token_entry = std::make_unique<base::DictionaryValue>();
no_token_entry->SetString("accountId", "No token in Token Service."); no_token_entry->SetString("accountId", "No token in Token Service.");
account_info->Append(std::move(no_token_entry)); 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>(); auto entry = std::make_unique<base::DictionaryValue>();
entry->SetString("accountId", account_id); entry->SetString("accountId", event.account_id);
entry->SetBoolean("hasRefreshToken", entry->SetString("timestamp", GetTimeStr(event.timestamp));
token_service->RefreshTokenIsAvailable(account_id)); entry->SetString("type", event.GetTypeAsString());
entry->SetBoolean("hasAuthError", entry->SetString("source", event.source);
token_service->RefreshTokenHasError(account_id)); refresh_token_events_value->Append(std::move(entry));
account_info->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; return signin_status;
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_ABOUT_SIGNIN_INTERNALS_H_ #ifndef COMPONENTS_SIGNIN_CORE_BROWSER_ABOUT_SIGNIN_INTERNALS_H_
#define COMPONENTS_SIGNIN_CORE_BROWSER_ABOUT_SIGNIN_INTERNALS_H_ #define COMPONENTS_SIGNIN_CORE_BROWSER_ABOUT_SIGNIN_INTERNALS_H_
#include <deque>
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
...@@ -122,6 +123,23 @@ class AboutSigninInternals ...@@ -122,6 +123,23 @@ class AboutSigninInternals
bool removed_; 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 // Encapsulates both authentication and token related information. Used
// by SigninInternals to maintain information that needs to be shown in // by SigninInternals to maintain information that needs to be shown in
// the about:signin-internals page. // the about:signin-internals page.
...@@ -132,6 +150,9 @@ class AboutSigninInternals ...@@ -132,6 +150,9 @@ class AboutSigninInternals
std::map<std::string, std::vector<std::unique_ptr<TokenInfo>>> std::map<std::string, std::vector<std::unique_ptr<TokenInfo>>>
token_info_map; token_info_map;
// All the events that affected the refresh tokens.
std::deque<RefreshTokenEvent> refresh_token_events;
SigninStatus(); SigninStatus();
~SigninStatus(); ~SigninStatus();
...@@ -139,6 +160,8 @@ class AboutSigninInternals ...@@ -139,6 +160,8 @@ class AboutSigninInternals
const std::string& consumer_id, const std::string& consumer_id,
const OAuth2TokenService::ScopeSet& scopes); const OAuth2TokenService::ScopeSet& scopes);
void AddRefreshTokenEvent(const RefreshTokenEvent& event);
// Returns a dictionary with the following form: // Returns a dictionary with the following form:
// { "signin_info" : // { "signin_info" :
// [ {"title": "Basic Information", // [ {"title": "Basic Information",
...@@ -186,6 +209,8 @@ class AboutSigninInternals ...@@ -186,6 +209,8 @@ class AboutSigninInternals
const OAuth2TokenService::ScopeSet& scopes) override; const OAuth2TokenService::ScopeSet& scopes) override;
// OAuth2TokenServiceDelegate::Observer implementations. // OAuth2TokenServiceDelegate::Observer implementations.
void OnRefreshTokenAvailable(const std::string& account_id) override;
void OnRefreshTokenRevoked(const std::string& account_id) override;
void OnRefreshTokensLoaded() override; void OnRefreshTokensLoaded() override;
void OnEndBatchChanges() override; void OnEndBatchChanges() override;
......
...@@ -89,6 +89,26 @@ ...@@ -89,6 +89,26 @@
</table> </table>
</div> </div>
</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/i18n_template.js"></script>
<script src="chrome://resources/js/jstemplate_compiled.js"></script> <script src="chrome://resources/js/jstemplate_compiled.js"></script>
<script src="chrome://signin-internals/signin_internals.js"></script> <script src="chrome://signin-internals/signin_internals.js"></script>
......
...@@ -169,6 +169,7 @@ function refreshSigninInfo(signinInfo) { ...@@ -169,6 +169,7 @@ function refreshSigninInfo(signinInfo) {
jstProcess(new JsEvalContext(signinInfo), $('signin-info')); jstProcess(new JsEvalContext(signinInfo), $('signin-info'));
jstProcess(new JsEvalContext(signinInfo), $('token-info')); jstProcess(new JsEvalContext(signinInfo), $('token-info'));
jstProcess(new JsEvalContext(signinInfo), $('account-info')); jstProcess(new JsEvalContext(signinInfo), $('account-info'));
jstProcess(new JsEvalContext(signinInfo), $('refresh-token-events'));
} }
// Replace the cookie information with the fetched values. // 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