0

[gaia] Read OAuth2 client secret and ID from gaia config

This CL adds an option of overriding OAauth2 client secret and ID via
gaia config that was introduced in https://crrev.com/c/2166197.

Gaia config makes switching between different Gaia environments easier.
Changing OAuth2 client secret and ID should be a part of this.

OAuth2 client parameters are set in google_api_keys.cc. In order to
access the gaia config from that file, gaia config has been moved into
a separate singleton class GaiaConfig. This class is used by both
google_api_keys.cc and gaia_urls.cc.

Skipping presubmit because google_api_keys_unittest.cc includes
non-header files. This triggers a presubmit error.

NOPRESUBMIT=true

Bug: 1072731
Change-Id: Iaf7e1342d1d4c31f627ff62fe3422059d9593642
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2245486
Reviewed-by: Mihai Sardarescu <msarda@chromium.org>
Commit-Queue: Alex Ilin <alexilin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#785368}
This commit is contained in:
Alex Ilin
2020-07-06 14:28:55 +00:00
committed by Commit Bot
parent f73405748c
commit 9ac2a9c49b
11 changed files with 378 additions and 146 deletions

@ -94,6 +94,8 @@ template("google_apis_tmpl") {
"gaia/gaia_auth_fetcher.h",
"gaia/gaia_auth_util.cc",
"gaia/gaia_auth_util.h",
"gaia/gaia_config.cc",
"gaia/gaia_config.h",
"gaia/gaia_constants.cc",
"gaia/gaia_constants.h",
"gaia/gaia_oauth_client.cc",
@ -264,6 +266,7 @@ bundle_data("google_apis_unittest_bundle_data") {
sources = [
"test/data/gaia/all_base_urls.json",
"test/data/gaia/all_urls.json",
"test/data/gaia/api_keys.json",
"test/data/gaia/bad_url.json",
"test/data/gaia/bad_url_key.json",
"test/data/gaia/bad_urls_key.json",

@ -0,0 +1,106 @@
// Copyright 2020 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.
#include "google_apis/gaia/gaia_config.h"
#include <memory>
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/no_destructor.h"
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "google_apis/gaia/gaia_switches.h"
#include "google_apis/google_api_keys.h"
#include "url/gurl.h"
namespace {
std::unique_ptr<GaiaConfig> ReadConfigFromDisk() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (!command_line->HasSwitch(switches::kGaiaConfig))
return nullptr;
const base::FilePath config_path =
command_line->GetSwitchValuePath(switches::kGaiaConfig);
std::string config_contents;
if (!base::ReadFileToString(config_path, &config_contents)) {
LOG(ERROR) << "Couldn't read gaia config file " << config_path;
return nullptr;
}
base::Optional<base::Value> dict = base::JSONReader::Read(config_contents);
if (!dict || !dict->is_dict()) {
LOG(ERROR) << "Couldn't parse gaia config file " << config_path;
return nullptr;
}
return std::make_unique<GaiaConfig>(std::move(dict.value()));
}
std::unique_ptr<GaiaConfig>* GetGlobalConfig() {
static base::NoDestructor<std::unique_ptr<GaiaConfig>> config(
ReadConfigFromDisk());
return config.get();
}
} // namespace
// static
GaiaConfig* GaiaConfig::GetInstance() {
return GetGlobalConfig()->get();
}
GaiaConfig::GaiaConfig(base::Value parsed_config)
: parsed_config_(std::move(parsed_config)) {}
GaiaConfig::~GaiaConfig() = default;
bool GaiaConfig::GetURLIfExists(base::StringPiece key, GURL* out_url) {
const base::Value* urls = parsed_config_.FindDictKey("urls");
if (!urls)
return false;
const base::Value* url_config = urls->FindDictKey(key);
if (!url_config)
return false;
const std::string* url_string = url_config->FindStringKey("url");
if (!url_string) {
LOG(ERROR) << "Incorrect format of \"" << key
<< "\" gaia config key. A key should contain {\"url\": "
"\"https://...\"} dictionary.";
return false;
}
GURL url = GURL(*url_string);
if (!url.is_valid()) {
LOG(ERROR) << "Invalid URL at \"" << key << "\" URL key";
return false;
}
*out_url = url;
return true;
}
bool GaiaConfig::GetAPIKeyIfExists(base::StringPiece key,
std::string* out_api_key) {
const base::Value* api_keys = parsed_config_.FindDictKey("api_keys");
if (!api_keys)
return false;
const std::string* api_key = api_keys->FindStringKey(key);
if (!api_key)
return false;
*out_api_key = *api_key;
return true;
}
// static
void GaiaConfig::ResetInstanceForTesting() {
*GetGlobalConfig() = ReadConfigFromDisk();
}

@ -0,0 +1,69 @@
// Copyright 2020 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.
#ifndef GOOGLE_APIS_GAIA_GAIA_CONFIG_H_
#define GOOGLE_APIS_GAIA_GAIA_CONFIG_H_
#include <memory>
#include "base/gtest_prod_util.h"
#include "base/optional.h"
#include "base/strings/string_piece_forward.h"
#include "base/values.h"
#include "google_apis/google_api_keys.h"
class GURL;
// Class representing a configuration for Gaia URLs and Google API keys.
// Parses a JSON config file specified by |switches::kGaiaConfig| and provides
// convenient getters for reading this config.
//
// The config is represented by a JSON object with the following structure:
// {
// "urls": {
// "gaia_url": {
// "url": "https://accounts.example.com"
// },
// ...
// }
// "api_keys": {
// "GOOGLE_CLIENT_ID_MAIN": "example_key",
// ...
// }
// }
class GaiaConfig {
public:
// Returns a global instance of GaiaConfig.
// This may return nullptr if the config file was not specified by a command
// line parameter or couldn't be parsed correctly.
static GaiaConfig* GetInstance();
// Constructs a new GaiaConfig from a parsed JSON dictionary.
// Prefer GetInstance() over this constructor.
explicit GaiaConfig(base::Value parsed_config);
~GaiaConfig();
// Searches for a URL by |key|.
// Returns true if |key| exists and contains a valid URL. |out_url| will be
// set to that URL.
// Otherwise, returns false. |out_url| will be unmodified.
bool GetURLIfExists(base::StringPiece key, GURL* out_url);
// Searches for an API key, OAuth2 client ID or secret by |key|.
// Returns true if |key| exists and contains a valid string.
// |out_api_key| will be set to that string.
// Otherwise, returns false. |out_api_key| will be unmodified.
bool GetAPIKeyIfExists(base::StringPiece key, std::string* out_api_key);
private:
friend class GaiaUrlsTest;
FRIEND_TEST_ALL_PREFIXES(GoogleAPIKeysTest, OverrideAllKeysUsingConfig);
// Re-reads the config from disk and resets the global instance of GaiaConfig.
static void ResetInstanceForTesting();
base::Value parsed_config_;
};
#endif // GOOGLE_APIS_GAIA_GAIA_CONFIG_H_

@ -5,14 +5,11 @@
#include "google_apis/gaia/gaia_urls.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "build/build_config.h"
#include "google_apis/gaia/gaia_config.h"
#include "google_apis/gaia/gaia_switches.h"
#include "google_apis/google_api_keys.h"
#include "url/url_canon.h"
@ -122,30 +119,6 @@ void ResolveURLIfInvalid(GURL* url_to_set,
}
}
void InitializeUrlFromConfig(const base::Value& urls,
base::StringPiece key,
GURL* out_value) {
const base::Value* url_config = urls.FindDictKey(key);
if (!url_config)
return;
const std::string* url_string = url_config->FindStringKey("url");
if (!url_string) {
LOG(ERROR) << "Incorrect format of \"" << key
<< "\" gaia config key. A key should contain {\"url\": "
"\"https://...\"} dictionary.";
return;
}
GURL url = GURL(*url_string);
if (!url.is_valid()) {
LOG(ERROR) << "Invalid URL at \"" << key << "\" URL key";
return;
}
*out_value = url;
}
} // namespace
GaiaUrls* GaiaUrls::GetInstance() {
@ -154,11 +127,7 @@ GaiaUrls* GaiaUrls::GetInstance() {
GaiaUrls::GaiaUrls() {
// Initialize all urls from a config first.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kGaiaConfig)) {
InitializeFromConfig(
command_line->GetSwitchValuePath(switches::kGaiaConfig));
}
InitializeFromConfig();
// Set a default value for all urls not set by the config.
InitializeDefault();
@ -416,70 +385,47 @@ void GaiaUrls::InitializeDefault() {
kOAuth2IssueTokenUrlSuffix);
}
void GaiaUrls::InitializeFromConfig(const base::FilePath& config_path) {
std::string config_contents;
if (!base::ReadFileToString(config_path, &config_contents)) {
LOG(ERROR) << "Couldn't read gaia config file " << config_path;
void GaiaUrls::InitializeFromConfig() {
GaiaConfig* config = GaiaConfig::GetInstance();
if (!config)
return;
}
base::Optional<base::Value> dict = base::JSONReader::Read(config_contents);
if (!dict || !dict->is_dict()) {
LOG(ERROR) << "Couldn't parse gaia config file " << config_path;
return;
}
const base::Value* url_dict = dict->FindDictKey("urls");
if (!url_dict) {
LOG(ERROR) << "Incorrect format of gaia config file. A config should "
"contain {\"urls\": {...}} dictionary.";
return;
}
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(google_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(secure_google_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(gaia_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(lso_origin_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(google_apis_origin_url));
InitializeUrlFromConfig(*url_dict,
URL_KEY_AND_PTR(oauth_account_manager_origin_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(captcha_base_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(client_login_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(service_login_url));
InitializeUrlFromConfig(*url_dict,
URL_KEY_AND_PTR(embedded_setup_chromeos_url_v2));
InitializeUrlFromConfig(*url_dict,
URL_KEY_AND_PTR(embedded_setup_windows_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(signin_chrome_sync_dice));
InitializeUrlFromConfig(*url_dict,
URL_KEY_AND_PTR(signin_chrome_sync_keys_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(service_login_auth_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(service_logout_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(continue_url_for_logout));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(get_user_info_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(token_auth_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(merge_session_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(get_oauth_token_url));
InitializeUrlFromConfig(*url_dict,
URL_KEY_AND_PTR(oauth_get_access_token_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(oauth_wrap_bridge_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(oauth_multilogin_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(oauth_user_info_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(oauth_revoke_token_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(oauth1_login_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(list_accounts_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(embedded_signin_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(add_account_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(reauth_url));
InitializeUrlFromConfig(*url_dict,
URL_KEY_AND_PTR(get_check_connection_info_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(oauth2_auth_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(oauth2_token_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(oauth2_issue_token_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(oauth2_token_info_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(oauth2_revoke_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(reauth_api_url));
InitializeUrlFromConfig(*url_dict, URL_KEY_AND_PTR(gaia_login_form_realm));
// TODO(crbug.com/1072731): add OAuth Client ID and secret.
config->GetURLIfExists(URL_KEY_AND_PTR(google_url));
config->GetURLIfExists(URL_KEY_AND_PTR(secure_google_url));
config->GetURLIfExists(URL_KEY_AND_PTR(gaia_url));
config->GetURLIfExists(URL_KEY_AND_PTR(lso_origin_url));
config->GetURLIfExists(URL_KEY_AND_PTR(google_apis_origin_url));
config->GetURLIfExists(URL_KEY_AND_PTR(oauth_account_manager_origin_url));
config->GetURLIfExists(URL_KEY_AND_PTR(captcha_base_url));
config->GetURLIfExists(URL_KEY_AND_PTR(client_login_url));
config->GetURLIfExists(URL_KEY_AND_PTR(service_login_url));
config->GetURLIfExists(URL_KEY_AND_PTR(embedded_setup_chromeos_url_v2));
config->GetURLIfExists(URL_KEY_AND_PTR(embedded_setup_windows_url));
config->GetURLIfExists(URL_KEY_AND_PTR(signin_chrome_sync_dice));
config->GetURLIfExists(URL_KEY_AND_PTR(signin_chrome_sync_keys_url));
config->GetURLIfExists(URL_KEY_AND_PTR(service_login_auth_url));
config->GetURLIfExists(URL_KEY_AND_PTR(service_logout_url));
config->GetURLIfExists(URL_KEY_AND_PTR(continue_url_for_logout));
config->GetURLIfExists(URL_KEY_AND_PTR(get_user_info_url));
config->GetURLIfExists(URL_KEY_AND_PTR(token_auth_url));
config->GetURLIfExists(URL_KEY_AND_PTR(merge_session_url));
config->GetURLIfExists(URL_KEY_AND_PTR(get_oauth_token_url));
config->GetURLIfExists(URL_KEY_AND_PTR(oauth_get_access_token_url));
config->GetURLIfExists(URL_KEY_AND_PTR(oauth_wrap_bridge_url));
config->GetURLIfExists(URL_KEY_AND_PTR(oauth_multilogin_url));
config->GetURLIfExists(URL_KEY_AND_PTR(oauth_user_info_url));
config->GetURLIfExists(URL_KEY_AND_PTR(oauth_revoke_token_url));
config->GetURLIfExists(URL_KEY_AND_PTR(oauth1_login_url));
config->GetURLIfExists(URL_KEY_AND_PTR(list_accounts_url));
config->GetURLIfExists(URL_KEY_AND_PTR(embedded_signin_url));
config->GetURLIfExists(URL_KEY_AND_PTR(add_account_url));
config->GetURLIfExists(URL_KEY_AND_PTR(reauth_url));
config->GetURLIfExists(URL_KEY_AND_PTR(get_check_connection_info_url));
config->GetURLIfExists(URL_KEY_AND_PTR(oauth2_auth_url));
config->GetURLIfExists(URL_KEY_AND_PTR(oauth2_token_url));
config->GetURLIfExists(URL_KEY_AND_PTR(oauth2_issue_token_url));
config->GetURLIfExists(URL_KEY_AND_PTR(oauth2_token_info_url));
config->GetURLIfExists(URL_KEY_AND_PTR(oauth2_revoke_url));
config->GetURLIfExists(URL_KEY_AND_PTR(reauth_api_url));
config->GetURLIfExists(URL_KEY_AND_PTR(gaia_login_form_realm));
}

@ -11,10 +11,6 @@
#include "base/memory/singleton.h"
#include "url/gurl.h"
namespace base {
class FilePath;
} // namespace base
// A signleton that provides all the URLs that are used for connecting to GAIA.
//
// Please update InitializeFromConfig() when adding new URLs.
@ -72,7 +68,7 @@ class GaiaUrls {
friend class GaiaUrlsTest;
void InitializeDefault();
void InitializeFromConfig(const base::FilePath& config_path);
void InitializeFromConfig();
GURL google_url_;
GURL secure_google_url_;

@ -11,6 +11,7 @@
#include "base/path_service.h"
#include "base/test/scoped_command_line.h"
#include "build/build_config.h"
#include "google_apis/gaia/gaia_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@ -44,8 +45,10 @@ class GaiaUrlsTest : public ::testing::Test {
// Lazily constructs |gaia_urls_|.
GaiaUrls* gaia_urls() {
if (!gaia_urls_)
if (!gaia_urls_) {
GaiaConfig::ResetInstanceForTesting();
gaia_urls_ = new GaiaUrls();
}
return gaia_urls_;
}

@ -5,7 +5,7 @@
#include "google_apis/google_api_keys.h"
// If you add more includes to this list, you also need to add them to
// google_api_keys_unittest.cc.
// google_api_keys_unittest.cc and google_api_keys_mac_unittest.mm.
#include <stddef.h>
@ -18,6 +18,7 @@
#include "base/logging.h"
#include "base/strings/stringize_macros.h"
#include "build/branding_buildflags.h"
#include "google_apis/gaia/gaia_config.h"
#include "google_apis/gaia/gaia_switches.h"
#if defined(OS_MACOSX)
@ -112,17 +113,18 @@ class APIKeyCache {
APIKeyCache() {
std::unique_ptr<base::Environment> environment(base::Environment::Create());
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
GaiaConfig* gaia_config = GaiaConfig::GetInstance();
api_key_ = CalculateKeyValue(
GOOGLE_API_KEY, STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY), nullptr,
std::string(), environment.get(), command_line);
std::string(), environment.get(), command_line, gaia_config);
// A special non-stable key is at the moment defined only for Android Chrome.
#if defined(OS_ANDROID)
api_key_non_stable_ = CalculateKeyValue(
GOOGLE_API_KEY_PHYSICAL_WEB_TEST,
STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_PHYSICAL_WEB_TEST), NULL,
std::string(), environment.get(), command_line);
GOOGLE_API_KEY_PHYSICAL_WEB_TEST,
STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_PHYSICAL_WEB_TEST), nullptr,
std::string(), environment.get(), command_line, gaia_config);
#else
api_key_non_stable_ = api_key_;
#endif
@ -130,73 +132,68 @@ class APIKeyCache {
api_key_remoting_ = CalculateKeyValue(
GOOGLE_API_KEY_REMOTING,
STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_REMOTING), nullptr, std::string(),
environment.get(), command_line);
environment.get(), command_line, gaia_config);
api_key_sharing_ = CalculateKeyValue(
GOOGLE_API_KEY_SHARING, STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_SHARING),
nullptr, std::string(), environment.get(), command_line);
nullptr, std::string(), environment.get(), command_line, gaia_config);
metrics_key_ = CalculateKeyValue(
GOOGLE_METRICS_SIGNING_KEY,
STRINGIZE_NO_EXPANSION(GOOGLE_METRICS_SIGNING_KEY), nullptr,
std::string(), environment.get(), command_line);
std::string(), environment.get(), command_line, gaia_config);
std::string default_client_id = CalculateKeyValue(
GOOGLE_DEFAULT_CLIENT_ID,
STRINGIZE_NO_EXPANSION(GOOGLE_DEFAULT_CLIENT_ID), nullptr,
std::string(), environment.get(), command_line);
std::string(), environment.get(), command_line, gaia_config);
std::string default_client_secret = CalculateKeyValue(
GOOGLE_DEFAULT_CLIENT_SECRET,
STRINGIZE_NO_EXPANSION(GOOGLE_DEFAULT_CLIENT_SECRET), nullptr,
std::string(), environment.get(), command_line);
std::string(), environment.get(), command_line, gaia_config);
// We currently only allow overriding the baked-in values for the
// default OAuth2 client ID and secret using a command-line
// argument, since that is useful to enable testing against
// argument and gaia config, since that is useful to enable testing against
// staging servers, and since that was what was possible and
// likely practiced by the QA team before this implementation was
// written.
client_ids_[CLIENT_MAIN] = CalculateKeyValue(
GOOGLE_CLIENT_ID_MAIN,
STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_MAIN),
switches::kOAuth2ClientID,
default_client_id,
environment.get(),
command_line);
client_secrets_[CLIENT_MAIN] = CalculateKeyValue(
GOOGLE_CLIENT_SECRET_MAIN,
STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_MAIN),
switches::kOAuth2ClientSecret,
default_client_secret,
environment.get(),
command_line);
GOOGLE_CLIENT_ID_MAIN, STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_MAIN),
switches::kOAuth2ClientID, default_client_id, environment.get(),
command_line, gaia_config);
client_secrets_[CLIENT_MAIN] =
CalculateKeyValue(GOOGLE_CLIENT_SECRET_MAIN,
STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_MAIN),
switches::kOAuth2ClientSecret, default_client_secret,
environment.get(), command_line, gaia_config);
client_ids_[CLIENT_CLOUD_PRINT] = CalculateKeyValue(
GOOGLE_CLIENT_ID_CLOUD_PRINT,
STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_CLOUD_PRINT), nullptr,
default_client_id, environment.get(), command_line);
default_client_id, environment.get(), command_line, gaia_config);
client_secrets_[CLIENT_CLOUD_PRINT] = CalculateKeyValue(
GOOGLE_CLIENT_SECRET_CLOUD_PRINT,
STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_CLOUD_PRINT), nullptr,
default_client_secret, environment.get(), command_line);
default_client_secret, environment.get(), command_line, gaia_config);
client_ids_[CLIENT_REMOTING] = CalculateKeyValue(
GOOGLE_CLIENT_ID_REMOTING,
STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_REMOTING), nullptr,
default_client_id, environment.get(), command_line);
default_client_id, environment.get(), command_line, gaia_config);
client_secrets_[CLIENT_REMOTING] = CalculateKeyValue(
GOOGLE_CLIENT_SECRET_REMOTING,
STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_REMOTING), nullptr,
default_client_secret, environment.get(), command_line);
default_client_secret, environment.get(), command_line, gaia_config);
client_ids_[CLIENT_REMOTING_HOST] = CalculateKeyValue(
GOOGLE_CLIENT_ID_REMOTING_HOST,
STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_REMOTING_HOST), nullptr,
default_client_id, environment.get(), command_line);
default_client_id, environment.get(), command_line, gaia_config);
client_secrets_[CLIENT_REMOTING_HOST] = CalculateKeyValue(
GOOGLE_CLIENT_SECRET_REMOTING_HOST,
STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_REMOTING_HOST), nullptr,
default_client_secret, environment.get(), command_line);
default_client_secret, environment.get(), command_line, gaia_config);
}
std::string api_key() const { return api_key_; }
@ -241,8 +238,11 @@ class APIKeyCache {
private:
// Gets a value for a key. In priority order, this will be the value
// provided via a command-line switch, the value provided via an
// environment variable, or finally a value baked into the build.
// provided via:
// 1. Command-line switch
// 2. Config file
// 3. Environment variable
// 4. Baked into the build
// |command_line_switch| may be NULL. Official Google Chrome builds will not
// use the value provided by an environment variable.
static std::string CalculateKeyValue(const char* baked_in_value,
@ -250,7 +250,8 @@ class APIKeyCache {
const char* command_line_switch,
const std::string& default_if_unset,
base::Environment* environment,
base::CommandLine* command_line) {
base::CommandLine* command_line,
GaiaConfig* gaia_config) {
std::string key_value = baked_in_value;
std::string temp;
#if defined(OS_MACOSX)
@ -275,6 +276,13 @@ class APIKeyCache {
}
#endif
if (gaia_config &&
gaia_config->GetAPIKeyIfExists(environment_variable_name, &temp)) {
key_value = temp;
VLOG(1) << "Overriding API key " << environment_variable_name
<< " with value " << key_value << " from gaia config.";
}
if (command_line_switch && command_line->HasSwitch(command_line_switch)) {
key_value = command_line->GetSwitchValueASCII(command_line_switch);
VLOG(1) << "Overriding API key " << environment_variable_name

@ -24,11 +24,17 @@
// https://developers.google.com/console/help/ and
// https://developers.google.com/console/.
//
// The keys must either be provided using preprocessor variables (set
// via e.g. ~/.gyp/include.gypi). Alternatively, in Chromium builds, they can be
// overridden at runtime using environment variables of the same name.
// Environment variable overrides will be ignored for official Google Chrome
// builds.
// The keys must either be provided using preprocessor variables (set via e.g.
// GN args). Alternatively, they can be overridden at runtime using one of the
// following methods (in priority order):
// - Command line parameters (only for GOOGLE_CLIENT_ID_MAIN and
// GOOGLE_CLIENT_SECRET_MAIN values). The command-line parameters are
// --oauth2-client-id and --oauth2-client-secret.
// - Config file entry of the same name. Path to a config file is set via the
// --gaia-config command line parameter. See google_apis/gaia/gaia_config.h
// for syntax reference.
// - Environment variables of the same name. Environment variable overrides will
// be ignored for official Google Chrome builds.
//
// The names of the preprocessor variables (or environment variables
// to override them at runtime in Chromium builds) are as follows:
@ -45,11 +51,6 @@
// (e.g. GOOGLE_CLIENT_SECRET_CLOUD_PRINT, i.e. one for each item in
// the OAuth2Client enumeration below)
//
// The GOOGLE_CLIENT_ID_MAIN and GOOGLE_CLIENT_SECRET_MAIN values can
// also be set via the command line (this overrides any other
// setting). The command-line parameters are --oauth2-client-id and
// --oauth2-client-secret.
//
// If some of the parameters mentioned above are not provided,
// Chromium will still build and run, but services that require them
// may fail to work without warning. They should do so gracefully,

@ -34,6 +34,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/strings/stringize_macros.h"
#include "google_apis/gaia/gaia_config.h"
#include "google_apis/google_api_keys_mac.h"
// After this test, for the remainder of this compilation unit, we

@ -12,10 +12,15 @@
#include "google_apis/google_api_keys_unittest.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/stl_util.h"
#include "base/test/scoped_command_line.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "google_apis/gaia/gaia_config.h"
#include "google_apis/gaia/gaia_switches.h"
#include "google_apis/google_api_keys.h"
// The Win builders fail (with a linker crash) when trying to link
// unit_tests, and the Android builders complain about multiply
@ -89,6 +94,17 @@ void GoogleAPIKeysTest::TearDown() {
// This is the default baked-in value for OAuth IDs and secrets.
static const char kDummyToken[] = "dummytoken";
base::FilePath GetTestFilePath(const std::string& relative_path) {
base::FilePath path;
if (!base::PathService::Get(base::DIR_SOURCE_ROOT, &path))
return base::FilePath();
return path.AppendASCII("google_apis")
.AppendASCII("test")
.AppendASCII("data")
.AppendASCII("gaia")
.AppendASCII(relative_path);
}
#if defined(USE_OFFICIAL_GOOGLE_API_KEYS)
// Test official build behavior, since we are in a checkout where this
// is possible.
@ -586,4 +602,70 @@ TEST_F(GoogleAPIKeysTest, OverrideAllKeysUsingSetters) {
}
#endif // defined(OS_IOS)
// Override all keys using both preprocessor defines and gaia config.
// Config should win.
namespace override_all_keys_config {
// We start every test by creating a clean environment for the
// preprocessor defines used in google_api_keys.cc
#undef DUMMY_API_TOKEN
#undef GOOGLE_API_KEY
#undef GOOGLE_CLIENT_ID_MAIN
#undef GOOGLE_CLIENT_SECRET_MAIN
#undef GOOGLE_CLIENT_ID_CLOUD_PRINT
#undef GOOGLE_CLIENT_SECRET_CLOUD_PRINT
#undef GOOGLE_CLIENT_ID_REMOTING
#undef GOOGLE_CLIENT_SECRET_REMOTING
#undef GOOGLE_CLIENT_ID_REMOTING_HOST
#undef GOOGLE_CLIENT_SECRET_REMOTING_HOST
#undef GOOGLE_DEFAULT_CLIENT_ID
#undef GOOGLE_DEFAULT_CLIENT_SECRET
#define GOOGLE_API_KEY "API_KEY"
#define GOOGLE_CLIENT_ID_MAIN "ID_MAIN"
#define GOOGLE_CLIENT_SECRET_MAIN "SECRET_MAIN"
#define GOOGLE_CLIENT_ID_CLOUD_PRINT "ID_CLOUD_PRINT"
#define GOOGLE_CLIENT_SECRET_CLOUD_PRINT "SECRET_CLOUD_PRINT"
#define GOOGLE_CLIENT_ID_REMOTING "ID_REMOTING"
#define GOOGLE_CLIENT_SECRET_REMOTING "SECRET_REMOTING"
#define GOOGLE_CLIENT_ID_REMOTING_HOST "ID_REMOTING_HOST"
#define GOOGLE_CLIENT_SECRET_REMOTING_HOST "SECRET_REMOTING_HOST"
// Undef include guard so things get defined again, within this namespace.
#undef GOOGLE_APIS_GOOGLE_API_KEYS_H_
#undef GOOGLE_APIS_INTERNAL_GOOGLE_CHROME_API_KEYS_
#include "google_apis/google_api_keys.cc"
} // namespace override_all_keys_config
TEST_F(GoogleAPIKeysTest, OverrideAllKeysUsingConfig) {
namespace testcase = override_all_keys_config::google_apis;
base::test::ScopedCommandLine command_line;
command_line.GetProcessCommandLine()->AppendSwitchPath(
"gaia-config", GetTestFilePath("api_keys.json"));
GaiaConfig::ResetInstanceForTesting();
EXPECT_TRUE(testcase::HasAPIKeyConfigured());
EXPECT_TRUE(testcase::HasOAuthClientConfigured());
EXPECT_EQ("config-API_KEY", testcase::GetAPIKey());
EXPECT_EQ("config-ID_MAIN",
testcase::GetOAuth2ClientID(testcase::CLIENT_MAIN));
EXPECT_EQ("config-SECRET_MAIN",
testcase::GetOAuth2ClientSecret(testcase::CLIENT_MAIN));
EXPECT_EQ("config-ID_CLOUD_PRINT",
testcase::GetOAuth2ClientID(testcase::CLIENT_CLOUD_PRINT));
EXPECT_EQ("config-SECRET_CLOUD_PRINT",
testcase::GetOAuth2ClientSecret(testcase::CLIENT_CLOUD_PRINT));
EXPECT_EQ("config-ID_REMOTING",
testcase::GetOAuth2ClientID(testcase::CLIENT_REMOTING));
EXPECT_EQ("config-SECRET_REMOTING",
testcase::GetOAuth2ClientSecret(testcase::CLIENT_REMOTING));
EXPECT_EQ("config-ID_REMOTING_HOST",
testcase::GetOAuth2ClientID(testcase::CLIENT_REMOTING_HOST));
EXPECT_EQ("config-SECRET_REMOTING_HOST",
testcase::GetOAuth2ClientSecret(testcase::CLIENT_REMOTING_HOST));
}
#endif // defined(OS_LINUX) || defined(OS_MACOSX)

@ -0,0 +1,17 @@
{
"api_keys": {
"GOOGLE_API_KEY": "config-API_KEY",
"GOOGLE_CLIENT_ID_MAIN": "config-ID_MAIN",
"GOOGLE_CLIENT_SECRET_MAIN": "config-SECRET_MAIN",
"GOOGLE_CLIENT_ID_CLOUD_PRINT": "config-ID_CLOUD_PRINT",
"GOOGLE_CLIENT_SECRET_CLOUD_PRINT": "config-SECRET_CLOUD_PRINT",
"GOOGLE_CLIENT_ID_REMOTING": "config-ID_REMOTING",
"GOOGLE_CLIENT_SECRET_REMOTING": "config-SECRET_REMOTING",
"GOOGLE_CLIENT_ID_REMOTING_HOST": "config-ID_REMOTING_HOST",
"GOOGLE_CLIENT_SECRET_REMOTING_HOST": "config-SECRET_REMOTING_HOST"
}
}