Add binary format to /ListAccounts responses.
This is a follow-up cl for crbug.com/357948173. We would like to add handling of binary response to /ListAccounts. The implementation is based on prototype crrev.com/5783859 and implements the new functionality behind a feature flag. Bug: 361268659 TEST=google_apis_unittests Change-Id: I1e35077c1d51f5400eee4883f2231ac5ea699fc4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6054254 Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com> Commit-Queue: Maciek Slusarczyk <mslus@chromium.org> Reviewed-by: Alex Ilin <alexilin@chromium.org> Reviewed-by: David Roger <droger@chromium.org> Cr-Commit-Position: refs/heads/main@{#1401364}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
9495326013
commit
d792e6e969
components/signin
internal
public
google_apis
@ -37,6 +37,7 @@
|
||||
#include "components/signin/public/identity_manager/set_accounts_in_cookie_result.h"
|
||||
#include "google_apis/credentials_mode.h"
|
||||
#include "google_apis/gaia/gaia_constants.h"
|
||||
#include "google_apis/gaia/gaia_features.h"
|
||||
#include "google_apis/gaia/gaia_id.h"
|
||||
#include "google_apis/gaia/gaia_urls.h"
|
||||
#include "google_apis/gaia/google_service_auth_error.h"
|
||||
@ -440,17 +441,27 @@ GaiaCookieManagerService::GaiaCookieManagerService(
|
||||
std::string gaia_cookie_last_list_accounts_data =
|
||||
signin_client_->GetPrefs()->GetString(
|
||||
prefs::kGaiaCookieLastListAccountsData);
|
||||
std::string gaia_cookie_last_list_accounts_binary_data =
|
||||
signin_client_->GetPrefs()->GetString(
|
||||
prefs::kGaiaCookieLastListAccountsBinaryData);
|
||||
|
||||
// Parse ListAccounts data from prefs. In case both jspb and protobuf encoded
|
||||
// data are present prefer the jspb one.
|
||||
bool parse_success = false;
|
||||
if (!gaia_cookie_last_list_accounts_data.empty()) {
|
||||
if (!gaia::ParseListAccountsData(gaia_cookie_last_list_accounts_data,
|
||||
&accounts_)) {
|
||||
DLOG(WARNING) << "GaiaCookieManagerService::ListAccounts: Failed to "
|
||||
"parse list accounts data from pref.";
|
||||
accounts_.clear();
|
||||
return;
|
||||
}
|
||||
InitializeListedAccountsIds();
|
||||
parse_success = gaia::ParseListAccountsData(
|
||||
gaia_cookie_last_list_accounts_data, &accounts_);
|
||||
} else if (!gaia_cookie_last_list_accounts_binary_data.empty()) {
|
||||
parse_success = gaia::ParseBinaryListAccountsData(
|
||||
gaia_cookie_last_list_accounts_binary_data, &accounts_);
|
||||
}
|
||||
if (!parse_success) {
|
||||
DLOG(WARNING) << "GaiaCookieManagerService::ListAccounts: Failed to "
|
||||
"parse list accounts data from pref.";
|
||||
accounts_.clear();
|
||||
return;
|
||||
}
|
||||
InitializeListedAccountsIds();
|
||||
}
|
||||
|
||||
GaiaCookieManagerService::~GaiaCookieManagerService() {
|
||||
@ -463,6 +474,8 @@ GaiaCookieManagerService::~GaiaCookieManagerService() {
|
||||
void GaiaCookieManagerService::RegisterPrefs(PrefRegistrySimple* registry) {
|
||||
registry->RegisterStringPref(prefs::kGaiaCookieLastListAccountsData,
|
||||
std::string());
|
||||
registry->RegisterStringPref(prefs::kGaiaCookieLastListAccountsBinaryData,
|
||||
std::string());
|
||||
}
|
||||
|
||||
void GaiaCookieManagerService::InitCookieListener() {
|
||||
@ -691,10 +704,16 @@ void GaiaCookieManagerService::OnListAccountsSuccess(const std::string& data) {
|
||||
GaiaCookieRequestType::LIST_ACCOUNTS);
|
||||
fetcher_backoff_.InformOfRequest(true);
|
||||
|
||||
if (!gaia::ParseListAccountsData(data, &accounts_)) {
|
||||
bool parse_success = base::FeatureList::IsEnabled(
|
||||
gaia::features::kListAccountsUsesBinaryFormat)
|
||||
? gaia::ParseBinaryListAccountsData(data, &accounts_)
|
||||
: gaia::ParseListAccountsData(data, &accounts_);
|
||||
if (!parse_success) {
|
||||
accounts_.clear();
|
||||
signin_client_->GetPrefs()->ClearPref(
|
||||
prefs::kGaiaCookieLastListAccountsData);
|
||||
signin_client_->GetPrefs()->ClearPref(
|
||||
prefs::kGaiaCookieLastListAccountsBinaryData);
|
||||
GoogleServiceAuthError error =
|
||||
GoogleServiceAuthError::FromUnexpectedServiceResponse(
|
||||
"Error parsing ListAccounts response");
|
||||
@ -702,8 +721,18 @@ void GaiaCookieManagerService::OnListAccountsSuccess(const std::string& data) {
|
||||
return;
|
||||
}
|
||||
|
||||
signin_client_->GetPrefs()->SetString(prefs::kGaiaCookieLastListAccountsData,
|
||||
data);
|
||||
if (base::FeatureList::IsEnabled(
|
||||
gaia::features::kListAccountsUsesBinaryFormat)) {
|
||||
signin_client_->GetPrefs()->SetString(
|
||||
prefs::kGaiaCookieLastListAccountsBinaryData, data);
|
||||
signin_client_->GetPrefs()->ClearPref(
|
||||
prefs::kGaiaCookieLastListAccountsData);
|
||||
} else {
|
||||
signin_client_->GetPrefs()->SetString(
|
||||
prefs::kGaiaCookieLastListAccountsData, data);
|
||||
signin_client_->GetPrefs()->ClearPref(
|
||||
prefs::kGaiaCookieLastListAccountsBinaryData);
|
||||
}
|
||||
RecordListAccountsFailure(GoogleServiceAuthError::NONE);
|
||||
|
||||
InitializeListedAccountsIds();
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "base/task/single_thread_task_runner.h"
|
||||
#include "base/test/metrics/histogram_tester.h"
|
||||
#include "base/test/mock_callback.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/test/test_mock_time_task_runner.h"
|
||||
#include "build/buildflag.h"
|
||||
@ -31,6 +32,7 @@
|
||||
#include "components/signin/public/identity_manager/set_accounts_in_cookie_result.h"
|
||||
#include "google_apis/gaia/core_account_id.h"
|
||||
#include "google_apis/gaia/gaia_constants.h"
|
||||
#include "google_apis/gaia/gaia_features.h"
|
||||
#include "google_apis/gaia/gaia_id.h"
|
||||
#include "google_apis/gaia/gaia_urls.h"
|
||||
#include "net/cookies/canonical_cookie.h"
|
||||
@ -950,6 +952,67 @@ TEST_F(GaiaCookieManagerServiceTest, GaiaCookieLastListAccountsDataSaved) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(GaiaCookieManagerServiceTest, ListAccountsEncodingMigration) {
|
||||
gaia::ListedAccount account;
|
||||
account.gaia_id = GaiaId("8");
|
||||
account.id = CoreAccountId::FromGaiaId(account.gaia_id);
|
||||
account.email = "a@b.com";
|
||||
account.raw_email = "a@b.com";
|
||||
signin::AccountsInCookieJarInfo cookies_expected_fresh(true, {account});
|
||||
signin::AccountsInCookieJarInfo cookies_expected_stale(false, {account});
|
||||
// ListAccounts data as jspb.
|
||||
std::string data_jspb =
|
||||
"[\"f\", [[\"b\", 0, \"n\", \"a@b.com\", \"p\", 0, 0, 0, 0, 1, \"8\"]]]";
|
||||
// ListAccounts data as base64-encoded protobuf.
|
||||
std::string data_binary = "Cg4aB2FAYi5jb21IAVIBOA==";
|
||||
{
|
||||
InstrumentedGaiaCookieManagerService helper(
|
||||
account_tracker_service(), token_service(), signin_client());
|
||||
MockObserver observer(&helper);
|
||||
EXPECT_EQ(helper.ListAccounts(), kCookiesEmptyStale);
|
||||
|
||||
// Default behaviour: return and store ListAccounts data encoded in jspb.
|
||||
SimulateListAccountsSuccess(&helper, data_jspb);
|
||||
ASSERT_EQ(helper.ListAccounts(), cookies_expected_fresh);
|
||||
EXPECT_EQ(signin_client()->GetPrefs()->GetString(
|
||||
prefs::kGaiaCookieLastListAccountsData),
|
||||
data_jspb);
|
||||
EXPECT_TRUE(signin_client()
|
||||
->GetPrefs()
|
||||
->GetString(prefs::kGaiaCookieLastListAccountsBinaryData)
|
||||
.empty());
|
||||
}
|
||||
|
||||
{
|
||||
// Enable the feature before reading prefs.
|
||||
base::test::ScopedFeatureList feature_list(
|
||||
gaia::features::kListAccountsUsesBinaryFormat);
|
||||
InstrumentedGaiaCookieManagerService helper(
|
||||
account_tracker_service(), token_service(), signin_client());
|
||||
MockObserver observer(&helper);
|
||||
// Verify that the jspb pref was read correctly.
|
||||
EXPECT_EQ(helper.ListAccounts(), cookies_expected_stale);
|
||||
|
||||
// Set and verify binary ListAccounts.
|
||||
SimulateListAccountsSuccess(&helper, data_binary);
|
||||
ASSERT_EQ(helper.ListAccounts(), cookies_expected_fresh);
|
||||
EXPECT_TRUE(signin_client()
|
||||
->GetPrefs()
|
||||
->GetString(prefs::kGaiaCookieLastListAccountsData)
|
||||
.empty());
|
||||
EXPECT_EQ(signin_client()->GetPrefs()->GetString(
|
||||
prefs::kGaiaCookieLastListAccountsBinaryData),
|
||||
data_binary);
|
||||
}
|
||||
|
||||
{
|
||||
InstrumentedGaiaCookieManagerService helper(
|
||||
account_tracker_service(), token_service(), signin_client());
|
||||
// Verify that the binary pref was read correctly.
|
||||
EXPECT_EQ(helper.ListAccounts(), cookies_expected_stale);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(GaiaCookieManagerServiceTest, ExternalCcResultFetcher) {
|
||||
InstrumentedGaiaCookieManagerService helper(account_tracker_service(),
|
||||
token_service(), signin_client());
|
||||
|
@ -108,10 +108,16 @@ const char kSignedInWithCredentialProvider[] =
|
||||
// Boolean which stores if the user is allowed to signin to chrome.
|
||||
const char kSigninAllowed[] = "signin.allowed";
|
||||
|
||||
// Contains last |ListAccounts| data which corresponds to Gaia cookies.
|
||||
// Contains last |ListAccounts| data which corresponds to Gaia cookies encoded
|
||||
// in jspb.
|
||||
const char kGaiaCookieLastListAccountsData[] =
|
||||
"gaia_cookie.last_list_accounts_data";
|
||||
|
||||
// Contains last |ListAccounts| data which corresponds to Gaia cookies in
|
||||
// base64-encoded protobuf.
|
||||
const char kGaiaCookieLastListAccountsBinaryData[] =
|
||||
"gaia_cookie.last_list_accounts_binary_data";
|
||||
|
||||
// The timestamp when History Sync was last declined (in the opt-in screen or
|
||||
// in the settings).
|
||||
// This value is reset when the user opts in to History Sync.
|
||||
|
@ -60,6 +60,8 @@ extern const char kSigninAllowed[];
|
||||
COMPONENT_EXPORT(SIGNIN_SWITCHES)
|
||||
extern const char kGaiaCookieLastListAccountsData[];
|
||||
COMPONENT_EXPORT(SIGNIN_SWITCHES)
|
||||
extern const char kGaiaCookieLastListAccountsBinaryData[];
|
||||
COMPONENT_EXPORT(SIGNIN_SWITCHES)
|
||||
extern const char kSigninAllowedOnNextStartup[];
|
||||
COMPONENT_EXPORT(SIGNIN_SWITCHES)
|
||||
extern const char kSigninInterceptionIDPCookiesUrl[];
|
||||
|
@ -133,6 +133,8 @@ component("google_apis") {
|
||||
"gaia/gaia_config.h",
|
||||
"gaia/gaia_constants.cc",
|
||||
"gaia/gaia_constants.h",
|
||||
"gaia/gaia_features.cc",
|
||||
"gaia/gaia_features.h",
|
||||
"gaia/gaia_id.cc",
|
||||
"gaia/gaia_id.h",
|
||||
"gaia/gaia_oauth_client.cc",
|
||||
@ -210,6 +212,7 @@ component("google_apis") {
|
||||
proto_library("proto") {
|
||||
sources = [
|
||||
"gaia/bound_oauth_token.proto",
|
||||
"gaia/list_accounts_response.proto",
|
||||
"gaia/oauth2_mint_token_consent_result.proto",
|
||||
]
|
||||
}
|
||||
@ -286,6 +289,7 @@ test("google_apis_unittests") {
|
||||
"//google_apis/common:common_unittests",
|
||||
"//testing/gmock",
|
||||
"//testing/gtest",
|
||||
"//third_party/protobuf:protobuf_lite",
|
||||
]
|
||||
|
||||
if (is_ios) {
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include "base/base64.h"
|
||||
#include "base/base64url.h"
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/functional/bind.h"
|
||||
@ -21,6 +22,7 @@
|
||||
#include "google_apis/gaia/bound_oauth_token.pb.h"
|
||||
#include "google_apis/gaia/gaia_id.h"
|
||||
#include "google_apis/gaia/gaia_urls.h"
|
||||
#include "google_apis/gaia/list_accounts_response.pb.h"
|
||||
#include "google_apis/gaia/oauth2_mint_token_consent_result.pb.h"
|
||||
#include "url/gurl.h"
|
||||
#include "url/origin.h"
|
||||
@ -203,6 +205,54 @@ bool ParseListAccountsData(std::string_view data,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseBinaryListAccountsData(const std::string& data,
|
||||
std::vector<ListedAccount>* accounts) {
|
||||
// Clear and rebuild our accounts list if one is given.
|
||||
if (accounts) {
|
||||
accounts->clear();
|
||||
}
|
||||
|
||||
// The input is expected to be base64-encoded.
|
||||
std::string decoded_data;
|
||||
if (!base::Base64Decode(data, &decoded_data,
|
||||
base::Base64DecodePolicy::kForgiving)) {
|
||||
VLOG(1) << "Failed to decode ListAccounts data as a Base64 String";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse our binary proto response.
|
||||
ListAccountsResponse parsed_result;
|
||||
if (!parsed_result.ParseFromString(decoded_data)) {
|
||||
VLOG(1) << "malformed ListAccountsResponse";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build a vector of accounts from the cookie. Order is important: the first
|
||||
// account in the list is the primary account.
|
||||
for (const auto& account : parsed_result.account()) {
|
||||
if (account.display_email().empty() || account.obfuscated_id().empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ListedAccount listed_account;
|
||||
listed_account.email = CanonicalizeEmail(account.display_email());
|
||||
listed_account.gaia_id = GaiaId(account.obfuscated_id());
|
||||
listed_account.valid = (
|
||||
// Assume the account is valid if unspecified for backcompat.
|
||||
account.has_valid_session() ? account.valid_session() : true);
|
||||
listed_account.signed_out =
|
||||
(account.has_signed_out() ? account.signed_out() : false);
|
||||
listed_account.verified =
|
||||
(account.has_is_verified() ? account.is_verified() : true);
|
||||
listed_account.raw_email = account.display_email();
|
||||
if (accounts) {
|
||||
accounts->push_back(std::move(listed_account));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseOAuth2MintTokenConsentResult(std::string_view consent_result,
|
||||
bool* approved,
|
||||
GaiaId* gaia_id) {
|
||||
|
@ -88,6 +88,16 @@ bool IsGoogleRobotAccountEmail(std::string_view email);
|
||||
// a GAIA origin and will in that case return false.
|
||||
COMPONENT_EXPORT(GOOGLE_APIS) bool HasGaiaSchemeHostPort(const GURL& url);
|
||||
|
||||
// Parses binary proto data returned by /ListAccounts call into the given
|
||||
// ListedAccounts. An email addresses is considered valid if a passive login
|
||||
// would succeed (i.e. the user does not need to reauthenticate).
|
||||
// If there was a parse error, this method returns false.
|
||||
// If |accounts| is null, the corresponding accounts returned from /ListAccounts
|
||||
// will be ignored.
|
||||
COMPONENT_EXPORT(GOOGLE_APIS)
|
||||
bool ParseBinaryListAccountsData(const std::string& data,
|
||||
std::vector<ListedAccount>* accounts);
|
||||
|
||||
// Parses JSON data returned by /ListAccounts call, returning a vector of
|
||||
// email/valid pairs. An email addresses is considered valid if a passive
|
||||
// login would succeed (i.e. the user does not need to reauthenticate).
|
||||
|
@ -4,9 +4,11 @@
|
||||
|
||||
#include "google_apis/gaia/gaia_auth_util.h"
|
||||
|
||||
#include "base/base64.h"
|
||||
#include "base/base64url.h"
|
||||
#include "google_apis/gaia/gaia_auth_test_util.h"
|
||||
#include "google_apis/gaia/gaia_id.h"
|
||||
#include "google_apis/gaia/list_accounts_response.pb.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "url/gurl.h"
|
||||
@ -47,6 +49,12 @@ ListedAccount NonverifiedListedAccount(const std::string& raw_email,
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string CreateBinaryListAccountsData(const ListAccountsResponse& response) {
|
||||
std::string serialized_response;
|
||||
response.SerializeToString(&serialized_response);
|
||||
return base::Base64Encode(serialized_response);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
using ::testing::ElementsAre;
|
||||
@ -314,6 +322,202 @@ TEST(GaiaAuthUtilTest, ParseListAccountsAcceptsNull) {
|
||||
nullptr));
|
||||
}
|
||||
|
||||
TEST(GaiaAuthUtilTest, ParseBinaryListAccountsData) {
|
||||
std::vector<ListedAccount> accounts;
|
||||
ListAccountsResponse response;
|
||||
|
||||
std::string serialized_empty_response;
|
||||
response.SerializeToString(&serialized_empty_response);
|
||||
std::string encoded_empty_response =
|
||||
base::Base64Encode(serialized_empty_response);
|
||||
ASSERT_TRUE(ParseBinaryListAccountsData(encoded_empty_response, &accounts));
|
||||
ASSERT_EQ(0u, accounts.size());
|
||||
|
||||
Account* account1 = response.add_account();
|
||||
account1->set_display_email("u@g.c");
|
||||
account1->set_valid_session(true);
|
||||
account1->set_obfuscated_id("45");
|
||||
|
||||
std::string encoded_one_account_response =
|
||||
CreateBinaryListAccountsData(response);
|
||||
ASSERT_TRUE(
|
||||
ParseBinaryListAccountsData(encoded_one_account_response, &accounts));
|
||||
ASSERT_EQ(1u, accounts.size());
|
||||
ASSERT_EQ("u@g.c", accounts[0].email);
|
||||
ASSERT_TRUE(accounts[0].valid);
|
||||
|
||||
Account* account2 = response.add_account();
|
||||
account2->set_display_email("u2@g.c");
|
||||
account2->set_valid_session(true);
|
||||
account2->set_obfuscated_id("6");
|
||||
|
||||
std::string encoded_two_accounts_response =
|
||||
CreateBinaryListAccountsData(response);
|
||||
ASSERT_TRUE(
|
||||
ParseBinaryListAccountsData(encoded_two_accounts_response, &accounts));
|
||||
ASSERT_EQ(2u, accounts.size());
|
||||
ASSERT_EQ("u@g.c", accounts[0].email);
|
||||
ASSERT_TRUE(accounts[0].valid);
|
||||
ASSERT_EQ("u2@g.c", accounts[1].email);
|
||||
ASSERT_TRUE(accounts[1].valid);
|
||||
|
||||
account1->set_display_email("U1@g.c");
|
||||
account1->set_obfuscated_id("45");
|
||||
account2->set_display_email("u.2@g.c");
|
||||
account2->set_obfuscated_id("46");
|
||||
|
||||
std::string encoded_noncanonical_account_response =
|
||||
CreateBinaryListAccountsData(response);
|
||||
ASSERT_TRUE(ParseBinaryListAccountsData(encoded_noncanonical_account_response,
|
||||
&accounts));
|
||||
ASSERT_EQ(2u, accounts.size());
|
||||
ASSERT_EQ(CanonicalizeEmail("U1@g.c"), accounts[0].email);
|
||||
ASSERT_TRUE(accounts[0].valid);
|
||||
ASSERT_EQ(CanonicalizeEmail("u.2@g.c"), accounts[1].email);
|
||||
ASSERT_TRUE(accounts[1].valid);
|
||||
}
|
||||
|
||||
TEST(GaiaAuthUtilTest, ParseBinaryListAccountsDataValidSession) {
|
||||
std::vector<ListedAccount> accounts;
|
||||
ListAccountsResponse response;
|
||||
|
||||
Account* account1 = response.add_account();
|
||||
account1->set_display_email("u@g.c");
|
||||
account1->set_valid_session(true);
|
||||
account1->set_obfuscated_id("45");
|
||||
|
||||
// Valid session is true means: return account.
|
||||
std::string encoded_one_account_response =
|
||||
CreateBinaryListAccountsData(response);
|
||||
ASSERT_TRUE(
|
||||
ParseBinaryListAccountsData(encoded_one_account_response, &accounts));
|
||||
ASSERT_EQ(1u, accounts.size());
|
||||
ASSERT_EQ("u@g.c", accounts[0].email);
|
||||
ASSERT_TRUE(accounts[0].valid);
|
||||
|
||||
// Valid session is false means: return account with valid bit false.
|
||||
account1->set_valid_session(false);
|
||||
std::string encoded_invalid_account_response =
|
||||
CreateBinaryListAccountsData(response);
|
||||
ASSERT_TRUE(
|
||||
ParseBinaryListAccountsData(encoded_invalid_account_response, &accounts));
|
||||
ASSERT_EQ(1u, accounts.size());
|
||||
ASSERT_EQ("u@g.c", accounts[0].email);
|
||||
ASSERT_FALSE(accounts[0].valid);
|
||||
}
|
||||
|
||||
TEST(GaiaAuthUtilTest, ParseBinaryListAccountsDataGaiaId) {
|
||||
std::vector<ListedAccount> accounts;
|
||||
ListAccountsResponse response;
|
||||
|
||||
Account* account1 = response.add_account();
|
||||
account1->set_display_email("u@g.c");
|
||||
account1->set_valid_session(true);
|
||||
|
||||
// Missing gaia id: do not return account.
|
||||
std::string encoded_no_gaia_id_response =
|
||||
CreateBinaryListAccountsData(response);
|
||||
ASSERT_TRUE(
|
||||
ParseBinaryListAccountsData(encoded_no_gaia_id_response, &accounts));
|
||||
ASSERT_EQ(0u, accounts.size());
|
||||
|
||||
account1->set_obfuscated_id("9863");
|
||||
|
||||
// Valid gaia session and gaia_id: return gaia session
|
||||
std::string encoded_with_gaia_session_response =
|
||||
CreateBinaryListAccountsData(response);
|
||||
ASSERT_TRUE(ParseBinaryListAccountsData(encoded_with_gaia_session_response,
|
||||
&accounts));
|
||||
ASSERT_EQ(1u, accounts.size());
|
||||
ASSERT_EQ("u@g.c", accounts[0].email);
|
||||
ASSERT_TRUE(accounts[0].valid);
|
||||
ASSERT_EQ("9863", accounts[0].gaia_id);
|
||||
}
|
||||
|
||||
TEST(GaiaAuthUtilTest, ParseBinaryListAccountsWithSignedOutAccounts) {
|
||||
std::vector<ListedAccount> accounts;
|
||||
ListAccountsResponse response;
|
||||
|
||||
Account* account1 = response.add_account();
|
||||
account1->set_display_email("u@g.c");
|
||||
account1->set_valid_session(true);
|
||||
account1->set_obfuscated_id("45");
|
||||
|
||||
Account* account2 = response.add_account();
|
||||
account2->set_display_email("u.2@g.c");
|
||||
account2->set_valid_session(true);
|
||||
account2->set_obfuscated_id("46");
|
||||
account2->set_signed_out(true);
|
||||
|
||||
std::string encoded_with_signed_out_session_response =
|
||||
CreateBinaryListAccountsData(response);
|
||||
ASSERT_TRUE(ParseBinaryListAccountsData(
|
||||
encoded_with_signed_out_session_response, &accounts));
|
||||
ASSERT_EQ(2u, accounts.size());
|
||||
ASSERT_EQ("u@g.c", accounts[0].email);
|
||||
ASSERT_FALSE(accounts[0].signed_out);
|
||||
ASSERT_EQ("u.2@g.c", accounts[1].email);
|
||||
ASSERT_TRUE(accounts[1].signed_out);
|
||||
}
|
||||
|
||||
TEST(GaiaAuthUtilTest, ParseBinaryListAccountsVerifiedAccounts) {
|
||||
std::vector<ListedAccount> accounts;
|
||||
ListAccountsResponse response;
|
||||
|
||||
Account* account1 = response.add_account();
|
||||
account1->set_display_email("a@g.c");
|
||||
account1->set_valid_session(true);
|
||||
account1->set_obfuscated_id("45");
|
||||
|
||||
Account* account2 = response.add_account();
|
||||
account2->set_display_email("b@g.c");
|
||||
account2->set_valid_session(true);
|
||||
account2->set_obfuscated_id("46");
|
||||
account2->set_signed_out(false);
|
||||
|
||||
Account* account3 = response.add_account();
|
||||
account3->set_display_email("c@g.c");
|
||||
account3->set_valid_session(true);
|
||||
account3->set_obfuscated_id("47");
|
||||
account3->set_signed_out(true);
|
||||
|
||||
std::string encoded_three_accounts_response =
|
||||
CreateBinaryListAccountsData(response);
|
||||
ASSERT_TRUE(
|
||||
ParseBinaryListAccountsData(encoded_three_accounts_response, &accounts));
|
||||
ASSERT_EQ(3u, accounts.size());
|
||||
ASSERT_EQ("a@g.c", accounts[0].email);
|
||||
EXPECT_TRUE(accounts[0].verified); // Accounts are not verified by default.
|
||||
EXPECT_FALSE(accounts[0].signed_out); // Accounts are not signed out by
|
||||
// default.
|
||||
ASSERT_EQ("b@g.c", accounts[1].email);
|
||||
EXPECT_TRUE(accounts[1].verified);
|
||||
EXPECT_FALSE(accounts[1].signed_out);
|
||||
ASSERT_EQ("c@g.c", accounts[2].email);
|
||||
EXPECT_TRUE(accounts[2].verified);
|
||||
EXPECT_TRUE(accounts[2].signed_out);
|
||||
}
|
||||
|
||||
TEST(GaiaAuthUtilTest, ParseBinaryListAccountsWithInvalidInput) {
|
||||
std::vector<ListedAccount> accounts;
|
||||
ListAccountsResponse response;
|
||||
|
||||
// Try to parse a malformed input string.
|
||||
std::string malformed_base64_response = "AAAAAAAAAAAAA";
|
||||
ASSERT_FALSE(
|
||||
ParseBinaryListAccountsData(malformed_base64_response, &accounts));
|
||||
|
||||
Account* account1 = response.add_account();
|
||||
account1->set_display_email("a@g.c");
|
||||
account1->set_valid_session(true);
|
||||
account1->set_obfuscated_id("45");
|
||||
std::string serialized_response;
|
||||
response.SerializeToString(&serialized_response);
|
||||
|
||||
// Try to parse serialized but not base64-encoded response.
|
||||
ASSERT_FALSE(ParseBinaryListAccountsData(serialized_response, &accounts));
|
||||
}
|
||||
|
||||
TEST(GaiaAuthUtilTest, ParseConsentResultApproved) {
|
||||
const char kApprovedConsent[] = "CAESCUVOQ1JZUFRFRBoMZmFrZV9nYWlhX2lk";
|
||||
EXPECT_EQ(kApprovedConsent,
|
||||
|
15
google_apis/gaia/gaia_features.cc
Normal file
15
google_apis/gaia/gaia_features.cc
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "google_apis/gaia/gaia_features.h"
|
||||
|
||||
namespace gaia::features {
|
||||
|
||||
// Enables binary format parsing in the /ListAccounts Gaia call. The endpoint
|
||||
// response depends on the presence of laf=b64bin parameter in the called url.
|
||||
BASE_FEATURE(kListAccountsUsesBinaryFormat,
|
||||
"ListAccountsUsesBinaryFormat",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
|
||||
} // namespace gaia::features
|
18
google_apis/gaia/gaia_features.h
Normal file
18
google_apis/gaia/gaia_features.h
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef GOOGLE_APIS_GAIA_GAIA_FEATURES_H_
|
||||
#define GOOGLE_APIS_GAIA_GAIA_FEATURES_H_
|
||||
|
||||
#include "base/component_export.h"
|
||||
#include "base/feature_list.h"
|
||||
|
||||
namespace gaia::features {
|
||||
|
||||
COMPONENT_EXPORT(GOOGLE_APIS)
|
||||
BASE_DECLARE_FEATURE(kListAccountsUsesBinaryFormat);
|
||||
|
||||
} // namespace gaia::features
|
||||
|
||||
#endif // GOOGLE_APIS_GAIA_GAIA_FEATURES_H_
|
@ -14,6 +14,7 @@
|
||||
#include "build/build_config.h"
|
||||
#include "build/chromeos_buildflags.h"
|
||||
#include "google_apis/gaia/gaia_config.h"
|
||||
#include "google_apis/gaia/gaia_features.h"
|
||||
#include "google_apis/gaia/gaia_switches.h"
|
||||
#include "google_apis/google_api_keys.h"
|
||||
#include "url/url_canon.h"
|
||||
@ -327,6 +328,11 @@ GURL GaiaUrls::ListAccountsURLWithSource(const std::string& source) {
|
||||
return list_accounts_url_;
|
||||
} else {
|
||||
std::string query = list_accounts_url_.query();
|
||||
if (base::FeatureList::IsEnabled(
|
||||
gaia::features::kListAccountsUsesBinaryFormat)) {
|
||||
return list_accounts_url_.Resolve(base::StringPrintf(
|
||||
"?gpsia=1&source=%s&laf=b64bin&%s", source.c_str(), query.c_str()));
|
||||
}
|
||||
return list_accounts_url_.Resolve(base::StringPrintf(
|
||||
"?gpsia=1&source=%s&%s", source.c_str(), query.c_str()));
|
||||
}
|
||||
|
@ -13,9 +13,11 @@
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/test/scoped_command_line.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "build/build_config.h"
|
||||
#include "build/chromeos_buildflags.h"
|
||||
#include "google_apis/gaia/gaia_config.h"
|
||||
#include "google_apis/gaia/gaia_features.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "url/gurl.h"
|
||||
@ -383,6 +385,20 @@ TEST_F(GaiaUrlsTest, InitializeFromConfig_AllBaseUrls) {
|
||||
"https://www.exampleapis.com/reauth/v1beta/users/");
|
||||
}
|
||||
|
||||
TEST_F(GaiaUrlsTest, InitializeDefault_ListAccountsFormat) {
|
||||
base::test::ScopedFeatureList feature_list;
|
||||
|
||||
// Default behaviour - kListAccountsUsesBinaryFormat disabled.
|
||||
EXPECT_EQ(gaia_urls()->ListAccountsURLWithSource("fake_source").spec(),
|
||||
"https://accounts.google.com/"
|
||||
"ListAccounts?gpsia=1&source=fake_source&json=standard");
|
||||
feature_list.InitAndEnableFeature(
|
||||
gaia::features::kListAccountsUsesBinaryFormat);
|
||||
EXPECT_EQ(gaia_urls()->ListAccountsURLWithSource("fake_source").spec(),
|
||||
"https://accounts.google.com/"
|
||||
"ListAccounts?gpsia=1&source=fake_source&laf=b64bin&json=standard");
|
||||
}
|
||||
|
||||
TEST_F(GaiaUrlsTest, InitializeFromConfigContents) {
|
||||
base::test::ScopedCommandLine command_line;
|
||||
command_line.GetProcessCommandLine()->AppendSwitchASCII(
|
||||
|
39
google_apis/gaia/list_accounts_response.proto
Normal file
39
google_apis/gaia/list_accounts_response.proto
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2024 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.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package gaia;
|
||||
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
// The state of a Gaia account.
|
||||
//
|
||||
// This is a projection of the type returned by Gaia's /ListAccounts, which only
|
||||
// has the fields that Chrome will use.
|
||||
message Account {
|
||||
// The display email for the account.
|
||||
optional string display_email = 3;
|
||||
|
||||
// If the session for this account is still 'valid' (not expired,
|
||||
// the account is not disabled, etc.). Only present for person accounts when
|
||||
// called with cookies as credentials.
|
||||
optional bool valid_session = 9;
|
||||
|
||||
// Obfuscated Gaia ID.
|
||||
optional string obfuscated_id = 10;
|
||||
|
||||
// Whether this account is only in the cookie and is actually signed out.
|
||||
optional bool signed_out = 14;
|
||||
|
||||
// Whether this account is verified.
|
||||
optional bool is_verified = 15;
|
||||
|
||||
// Internal Fields.
|
||||
reserved 1, 2, 4, 5, 6, 7, 8, 11, 12, 13;
|
||||
}
|
||||
|
||||
message ListAccountsResponse {
|
||||
repeated Account account = 1;
|
||||
}
|
Reference in New Issue
Block a user