blob: a36389dec87dc21b2dabea6403d6e797f10b624c [file] [log] [blame]
// Copyright (c) 2012 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_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_switches.h"
#include "google_apis/google_api_keys.h"
#include "url/url_canon.h"
#include "url/url_constants.h"
#define CONCAT_HIDDEN(a, b) a##b
#define CONCAT(a, b) CONCAT_HIDDEN(a, b)
#define URL_KEY_AND_PTR(name) #name, &CONCAT(name, _)
namespace {
// Gaia service constants
const char kDefaultGoogleUrl[] = "http://google.com";
const char kDefaultGaiaUrl[] = "https://accounts.google.com";
const char kDefaultGoogleApisBaseUrl[] = "https://www.googleapis.com";
const char kDefaultOAuthAccountManagerBaseUrl[] =
"https://oauthaccountmanager.googleapis.com";
// API calls from accounts.google.com
const char kClientLoginUrlSuffix[] = "ClientLogin";
const char kServiceLoginUrlSuffix[] = "ServiceLogin";
const char kEmbeddedSetupChromeOsUrlSuffixV2[] = "embedded/setup/v2/chromeos";
const char kEmbeddedSetupWindowsUrlSuffix[] = "embedded/setup/windows";
// Parameter "ssp=1" is used to skip showing the password bubble when a user
// signs in to Chrome. Note that Gaia will pass this client specified parameter
// to all URLs that are loaded as part of thi sign-in flow.
const char kSigninChromeSyncDice[] = "signin/chrome/sync?ssp=1";
#if defined(OS_ANDROID)
const char kSigninChromeSyncKeysUrl[] = "encryption/unlock/android";
#elif defined(OS_IOS)
const char kSigninChromeSyncKeysUrl[] = "encryption/unlock/ios";
#elif defined(OS_CHROMEOS)
const char kSigninChromeSyncKeysUrl[] = "encryption/unlock/chromeos";
#else
const char kSigninChromeSyncKeysUrl[] = "encryption/unlock/desktop";
#endif
const char kServiceLoginAuthUrlSuffix[] = "ServiceLoginAuth";
const char kServiceLogoutUrlSuffix[] = "Logout";
const char kContinueUrlForLogoutSuffix[] = "chrome/blank.html";
const char kGetUserInfoUrlSuffix[] = "GetUserInfo";
const char kTokenAuthUrlSuffix[] = "TokenAuth";
const char kMergeSessionUrlSuffix[] = "MergeSession";
const char kOAuthGetAccessTokenUrlSuffix[] = "OAuthGetAccessToken";
const char kOAuthWrapBridgeUrlSuffix[] = "OAuthWrapBridge";
const char kOAuth1LoginUrlSuffix[] = "OAuthLogin";
const char kOAuthMultiloginSuffix[] = "oauth/multilogin";
const char kOAuthRevokeTokenUrlSuffix[] = "AuthSubRevokeToken";
const char kListAccountsSuffix[] = "ListAccounts?json=standard";
const char kEmbeddedSigninSuffix[] = "embedded/setup/chrome/usermenu";
const char kAddAccountSuffix[] = "AddSession";
const char kReauthSuffix[] = "embedded/xreauth/chrome";
const char kGetCheckConnectionInfoSuffix[] = "GetCheckConnectionInfo";
// API calls from accounts.google.com (LSO)
const char kGetOAuthTokenUrlSuffix[] = "o/oauth/GetOAuthToken/";
const char kOAuth2AuthUrlSuffix[] = "o/oauth2/auth";
const char kOAuth2RevokeUrlSuffix[] = "o/oauth2/revoke";
// API calls from www.googleapis.com
const char kOAuth2TokenUrlSuffix[] = "oauth2/v4/token";
const char kOAuth2TokenInfoUrlSuffix[] = "oauth2/v2/tokeninfo";
const char kOAuthUserInfoUrlSuffix[] = "oauth2/v1/userinfo";
const char kReAuthApiUrlSuffix[] = "reauth/v1beta/users/";
// API calls from oauthaccountmanager.googleapis.com
const char kOAuth2IssueTokenUrlSuffix[] = "v1/issuetoken";
void GetSwitchValueWithDefault(base::StringPiece switch_value,
base::StringPiece default_value,
std::string* output_value) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switch_value)) {
*output_value = command_line->GetSwitchValueASCII(switch_value);
} else {
*output_value = default_value.as_string();
}
}
GURL GetURLSwitchValueWithDefault(base::StringPiece switch_value,
base::StringPiece default_value) {
std::string string_value;
GetSwitchValueWithDefault(switch_value, default_value, &string_value);
const GURL result(string_value);
if (result.is_valid()) {
return result;
}
LOG(ERROR) << "Ignoring invalid URL \"" << string_value << "\" for switch \""
<< switch_value << "\"";
return GURL(default_value);
}
void SetDefaultURLIfInvalid(GURL* url_to_set,
base::StringPiece switch_value,
base::StringPiece default_value) {
if (!url_to_set->is_valid()) {
*url_to_set = GetURLSwitchValueWithDefault(switch_value, default_value);
}
}
void ResolveURLIfInvalid(GURL* url_to_set,
const GURL& base_url,
base::StringPiece suffix) {
if (!url_to_set->is_valid()) {
*url_to_set = base_url.Resolve(suffix);
}
}
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() {
return base::Singleton<GaiaUrls>::get();
}
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));
}
// Set a default value for all urls not set by the config.
InitializeDefault();
}
GaiaUrls::~GaiaUrls() = default;
const GURL& GaiaUrls::google_url() const {
return google_url_;
}
const GURL& GaiaUrls::secure_google_url() const {
return secure_google_url_;
}
const GURL& GaiaUrls::gaia_url() const {
return gaia_url_;
}
const GURL& GaiaUrls::captcha_base_url() const {
return captcha_base_url_;
}
const GURL& GaiaUrls::client_login_url() const {
return client_login_url_;
}
const GURL& GaiaUrls::service_login_url() const {
return service_login_url_;
}
const GURL& GaiaUrls::embedded_setup_chromeos_url(unsigned version) const {
DCHECK_EQ(version, 2U);
return embedded_setup_chromeos_url_v2_;
}
const GURL& GaiaUrls::embedded_setup_windows_url() const {
return embedded_setup_windows_url_;
}
const GURL& GaiaUrls::signin_chrome_sync_dice() const {
return signin_chrome_sync_dice_;
}
const GURL& GaiaUrls::signin_chrome_sync_keys_url() const {
return signin_chrome_sync_keys_url_;
}
const GURL& GaiaUrls::service_login_auth_url() const {
return service_login_auth_url_;
}
const GURL& GaiaUrls::service_logout_url() const {
return service_logout_url_;
}
const GURL& GaiaUrls::get_user_info_url() const {
return get_user_info_url_;
}
const GURL& GaiaUrls::token_auth_url() const {
return token_auth_url_;
}
const GURL& GaiaUrls::merge_session_url() const {
return merge_session_url_;
}
const GURL& GaiaUrls::get_oauth_token_url() const {
return get_oauth_token_url_;
}
const GURL& GaiaUrls::oauth_multilogin_url() const {
return oauth_multilogin_url_;
}
const GURL& GaiaUrls::oauth_get_access_token_url() const {
return oauth_get_access_token_url_;
}
const GURL& GaiaUrls::oauth_wrap_bridge_url() const {
return oauth_wrap_bridge_url_;
}
const GURL& GaiaUrls::oauth_user_info_url() const {
return oauth_user_info_url_;
}
const GURL& GaiaUrls::oauth_revoke_token_url() const {
return oauth_revoke_token_url_;
}
const GURL& GaiaUrls::oauth1_login_url() const {
return oauth1_login_url_;
}
const GURL& GaiaUrls::embedded_signin_url() const {
return embedded_signin_url_;
}
const GURL& GaiaUrls::add_account_url() const {
return add_account_url_;
}
const GURL& GaiaUrls::reauth_url() const {
return reauth_url_;
}
const std::string& GaiaUrls::oauth2_chrome_client_id() const {
return oauth2_chrome_client_id_;
}
const std::string& GaiaUrls::oauth2_chrome_client_secret() const {
return oauth2_chrome_client_secret_;
}
const GURL& GaiaUrls::oauth2_auth_url() const {
return oauth2_auth_url_;
}
const GURL& GaiaUrls::oauth2_token_url() const {
return oauth2_token_url_;
}
const GURL& GaiaUrls::oauth2_issue_token_url() const {
return oauth2_issue_token_url_;
}
const GURL& GaiaUrls::oauth2_token_info_url() const {
return oauth2_token_info_url_;
}
const GURL& GaiaUrls::oauth2_revoke_url() const {
return oauth2_revoke_url_;
}
const GURL& GaiaUrls::reauth_api_url() const {
return reauth_api_url_;
}
const GURL& GaiaUrls::gaia_login_form_realm() const {
return gaia_url_;
}
GURL GaiaUrls::ListAccountsURLWithSource(const std::string& source) {
if (source.empty()) {
return list_accounts_url_;
} else {
std::string query = list_accounts_url_.query();
return list_accounts_url_.Resolve(base::StringPrintf(
"?gpsia=1&source=%s&%s", source.c_str(), query.c_str()));
}
}
GURL GaiaUrls::LogOutURLWithSource(const std::string& source) {
std::string params =
source.empty()
? base::StringPrintf("?continue=%s",
continue_url_for_logout_.spec().c_str())
: base::StringPrintf("?source=%s&continue=%s", source.c_str(),
continue_url_for_logout_.spec().c_str());
return service_logout_url_.Resolve(params);
}
GURL GaiaUrls::GetCheckConnectionInfoURLWithSource(const std::string& source) {
return source.empty() ? get_check_connection_info_url_
: get_check_connection_info_url_.Resolve(
base::StringPrintf("?source=%s", source.c_str()));
}
void GaiaUrls::InitializeDefault() {
SetDefaultURLIfInvalid(&google_url_, switches::kGoogleUrl, kDefaultGoogleUrl);
SetDefaultURLIfInvalid(&gaia_url_, switches::kGaiaUrl, kDefaultGaiaUrl);
SetDefaultURLIfInvalid(&lso_origin_url_, switches::kLsoUrl, kDefaultGaiaUrl);
SetDefaultURLIfInvalid(&google_apis_origin_url_, switches::kGoogleApisUrl,
kDefaultGoogleApisBaseUrl);
SetDefaultURLIfInvalid(&oauth_account_manager_origin_url_,
switches::kOAuthAccountManagerUrl,
kDefaultOAuthAccountManagerBaseUrl);
if (!secure_google_url_.is_valid()) {
url::Replacements<char> scheme_replacement;
scheme_replacement.SetScheme(url::kHttpsScheme,
url::Component(0, strlen(url::kHttpsScheme)));
secure_google_url_ = google_url_.ReplaceComponents(scheme_replacement);
}
if (!captcha_base_url_.is_valid()) {
captcha_base_url_ =
GURL("http://" + gaia_url_.host() +
(gaia_url_.has_port() ? ":" + gaia_url_.port() : ""));
}
oauth2_chrome_client_id_ =
google_apis::GetOAuth2ClientID(google_apis::CLIENT_MAIN);
oauth2_chrome_client_secret_ =
google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_MAIN);
// URLs from |gaia_url_|.
ResolveURLIfInvalid(&client_login_url_, gaia_url_, kClientLoginUrlSuffix);
ResolveURLIfInvalid(&service_login_url_, gaia_url_, kServiceLoginUrlSuffix);
ResolveURLIfInvalid(&embedded_setup_chromeos_url_v2_, gaia_url_,
kEmbeddedSetupChromeOsUrlSuffixV2);
ResolveURLIfInvalid(&embedded_setup_windows_url_, gaia_url_,
kEmbeddedSetupWindowsUrlSuffix);
ResolveURLIfInvalid(&signin_chrome_sync_dice_, gaia_url_,
kSigninChromeSyncDice);
ResolveURLIfInvalid(&signin_chrome_sync_keys_url_, gaia_url_,
kSigninChromeSyncKeysUrl);
ResolveURLIfInvalid(&service_login_auth_url_, gaia_url_,
kServiceLoginAuthUrlSuffix);
ResolveURLIfInvalid(&service_logout_url_, gaia_url_, kServiceLogoutUrlSuffix);
ResolveURLIfInvalid(&continue_url_for_logout_, gaia_url_,
kContinueUrlForLogoutSuffix);
ResolveURLIfInvalid(&get_user_info_url_, gaia_url_, kGetUserInfoUrlSuffix);
ResolveURLIfInvalid(&token_auth_url_, gaia_url_, kTokenAuthUrlSuffix);
ResolveURLIfInvalid(&merge_session_url_, gaia_url_, kMergeSessionUrlSuffix);
ResolveURLIfInvalid(&oauth_multilogin_url_, gaia_url_,
kOAuthMultiloginSuffix);
ResolveURLIfInvalid(&oauth_get_access_token_url_, gaia_url_,
kOAuthGetAccessTokenUrlSuffix);
ResolveURLIfInvalid(&oauth_wrap_bridge_url_, gaia_url_,
kOAuthWrapBridgeUrlSuffix);
ResolveURLIfInvalid(&oauth_revoke_token_url_, gaia_url_,
kOAuthRevokeTokenUrlSuffix);
ResolveURLIfInvalid(&oauth1_login_url_, gaia_url_, kOAuth1LoginUrlSuffix);
ResolveURLIfInvalid(&list_accounts_url_, gaia_url_, kListAccountsSuffix);
ResolveURLIfInvalid(&embedded_signin_url_, gaia_url_, kEmbeddedSigninSuffix);
ResolveURLIfInvalid(&add_account_url_, gaia_url_, kAddAccountSuffix);
ResolveURLIfInvalid(&reauth_url_, gaia_url_, kReauthSuffix);
ResolveURLIfInvalid(&get_check_connection_info_url_, gaia_url_,
kGetCheckConnectionInfoSuffix);
if (!gaia_login_form_realm_.is_valid()) {
gaia_login_form_realm_ = gaia_url_;
}
// URLs from |lso_origin_url_|.
ResolveURLIfInvalid(&get_oauth_token_url_, lso_origin_url_,
kGetOAuthTokenUrlSuffix);
ResolveURLIfInvalid(&oauth2_auth_url_, lso_origin_url_, kOAuth2AuthUrlSuffix);
ResolveURLIfInvalid(&oauth2_revoke_url_, lso_origin_url_,
kOAuth2RevokeUrlSuffix);
// URLs from |google_apis_origin_url_|.
ResolveURLIfInvalid(&oauth2_token_url_, google_apis_origin_url_,
kOAuth2TokenUrlSuffix);
ResolveURLIfInvalid(&oauth2_token_info_url_, google_apis_origin_url_,
kOAuth2TokenInfoUrlSuffix);
ResolveURLIfInvalid(&oauth_user_info_url_, google_apis_origin_url_,
kOAuthUserInfoUrlSuffix);
ResolveURLIfInvalid(&reauth_api_url_, google_apis_origin_url_,
kReAuthApiUrlSuffix);
// URLs from |oauth_account_manager_origin_url_|.
ResolveURLIfInvalid(&oauth2_issue_token_url_,
oauth_account_manager_origin_url_,
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;
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.
}