1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "google_apis/google_api_keys.h" 6 7 // If you add more includes to this list, you also need to add them to 8 // google_api_keys_unittest.cc. 9 #include "base/command_line.h" 10 #include "base/environment.h" 11 #include "base/lazy_instance.h" 12 #include "base/logging.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/strings/stringize_macros.h" 15 #include "google_apis/gaia/gaia_switches.h" 16 17 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_OFFICIAL_GOOGLE_API_KEYS) 18 #include "google_apis/internal/google_chrome_api_keys.h" 19 #endif 20 21 // Used to indicate an unset key/id/secret. This works better with 22 // various unit tests than leaving the token empty. 23 #define DUMMY_API_TOKEN "dummytoken" 24 25 #if !defined(GOOGLE_API_KEY) 26 #define GOOGLE_API_KEY DUMMY_API_TOKEN 27 #endif 28 29 #if !defined(GOOGLE_CLIENT_ID_MAIN) 30 #define GOOGLE_CLIENT_ID_MAIN DUMMY_API_TOKEN 31 #endif 32 33 #if !defined(GOOGLE_CLIENT_SECRET_MAIN) 34 #define GOOGLE_CLIENT_SECRET_MAIN DUMMY_API_TOKEN 35 #endif 36 37 #if !defined(GOOGLE_CLIENT_ID_CLOUD_PRINT) 38 #define GOOGLE_CLIENT_ID_CLOUD_PRINT DUMMY_API_TOKEN 39 #endif 40 41 #if !defined(GOOGLE_CLIENT_SECRET_CLOUD_PRINT) 42 #define GOOGLE_CLIENT_SECRET_CLOUD_PRINT DUMMY_API_TOKEN 43 #endif 44 45 #if !defined(GOOGLE_CLIENT_ID_REMOTING) 46 #define GOOGLE_CLIENT_ID_REMOTING DUMMY_API_TOKEN 47 #endif 48 49 #if !defined(GOOGLE_CLIENT_SECRET_REMOTING) 50 #define GOOGLE_CLIENT_SECRET_REMOTING DUMMY_API_TOKEN 51 #endif 52 53 #if !defined(GOOGLE_CLIENT_ID_REMOTING_HOST) 54 #define GOOGLE_CLIENT_ID_REMOTING_HOST DUMMY_API_TOKEN 55 #endif 56 57 #if !defined(GOOGLE_CLIENT_SECRET_REMOTING_HOST) 58 #define GOOGLE_CLIENT_SECRET_REMOTING_HOST DUMMY_API_TOKEN 59 #endif 60 61 // These are used as shortcuts for developers and users providing 62 // OAuth credentials via preprocessor defines or environment 63 // variables. If set, they will be used to replace any of the client 64 // IDs and secrets above that have not been set (and only those; they 65 // will not override already-set values). 66 #if !defined(GOOGLE_DEFAULT_CLIENT_ID) 67 #define GOOGLE_DEFAULT_CLIENT_ID "" 68 #endif 69 #if !defined(GOOGLE_DEFAULT_CLIENT_SECRET) 70 #define GOOGLE_DEFAULT_CLIENT_SECRET "" 71 #endif 72 73 namespace google_apis { 74 75 // This is used as a lazy instance to determine keys once and cache them. 76 class APIKeyCache { 77 public: 78 APIKeyCache() { 79 scoped_ptr<base::Environment> environment(base::Environment::Create()); 80 CommandLine* command_line = CommandLine::ForCurrentProcess(); 81 82 api_key_ = CalculateKeyValue(GOOGLE_API_KEY, 83 STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY), 84 NULL, 85 std::string(), 86 environment.get(), 87 command_line); 88 89 std::string default_client_id = 90 CalculateKeyValue(GOOGLE_DEFAULT_CLIENT_ID, 91 STRINGIZE_NO_EXPANSION(GOOGLE_DEFAULT_CLIENT_ID), 92 NULL, 93 std::string(), 94 environment.get(), 95 command_line); 96 std::string default_client_secret = 97 CalculateKeyValue(GOOGLE_DEFAULT_CLIENT_SECRET, 98 STRINGIZE_NO_EXPANSION(GOOGLE_DEFAULT_CLIENT_SECRET), 99 NULL, 100 std::string(), 101 environment.get(), 102 command_line); 103 104 // We currently only allow overriding the baked-in values for the 105 // default OAuth2 client ID and secret using a command-line 106 // argument, since that is useful to enable testing against 107 // staging servers, and since that was what was possible and 108 // likely practiced by the QA team before this implementation was 109 // written. 110 client_ids_[CLIENT_MAIN] = CalculateKeyValue( 111 GOOGLE_CLIENT_ID_MAIN, 112 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_MAIN), 113 switches::kOAuth2ClientID, 114 default_client_id, 115 environment.get(), 116 command_line); 117 client_secrets_[CLIENT_MAIN] = CalculateKeyValue( 118 GOOGLE_CLIENT_SECRET_MAIN, 119 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_MAIN), 120 switches::kOAuth2ClientSecret, 121 default_client_secret, 122 environment.get(), 123 command_line); 124 125 client_ids_[CLIENT_CLOUD_PRINT] = CalculateKeyValue( 126 GOOGLE_CLIENT_ID_CLOUD_PRINT, 127 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_CLOUD_PRINT), 128 NULL, 129 default_client_id, 130 environment.get(), 131 command_line); 132 client_secrets_[CLIENT_CLOUD_PRINT] = CalculateKeyValue( 133 GOOGLE_CLIENT_SECRET_CLOUD_PRINT, 134 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_CLOUD_PRINT), 135 NULL, 136 default_client_secret, 137 environment.get(), 138 command_line); 139 140 client_ids_[CLIENT_REMOTING] = CalculateKeyValue( 141 GOOGLE_CLIENT_ID_REMOTING, 142 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_REMOTING), 143 NULL, 144 default_client_id, 145 environment.get(), 146 command_line); 147 client_secrets_[CLIENT_REMOTING] = CalculateKeyValue( 148 GOOGLE_CLIENT_SECRET_REMOTING, 149 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_REMOTING), 150 NULL, 151 default_client_secret, 152 environment.get(), 153 command_line); 154 155 client_ids_[CLIENT_REMOTING_HOST] = CalculateKeyValue( 156 GOOGLE_CLIENT_ID_REMOTING_HOST, 157 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_REMOTING_HOST), 158 NULL, 159 default_client_id, 160 environment.get(), 161 command_line); 162 client_secrets_[CLIENT_REMOTING_HOST] = CalculateKeyValue( 163 GOOGLE_CLIENT_SECRET_REMOTING_HOST, 164 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_REMOTING_HOST), 165 NULL, 166 default_client_secret, 167 environment.get(), 168 command_line); 169 } 170 171 std::string api_key() const { return api_key_; } 172 173 std::string GetClientID(OAuth2Client client) const { 174 DCHECK_LT(client, CLIENT_NUM_ITEMS); 175 return client_ids_[client]; 176 } 177 178 std::string GetClientSecret(OAuth2Client client) const { 179 DCHECK_LT(client, CLIENT_NUM_ITEMS); 180 return client_secrets_[client]; 181 } 182 183 private: 184 // Gets a value for a key. In priority order, this will be the value 185 // provided via a command-line switch, the value provided via an 186 // environment variable, or finally a value baked into the build. 187 // |command_line_switch| may be NULL. 188 static std::string CalculateKeyValue(const char* baked_in_value, 189 const char* environment_variable_name, 190 const char* command_line_switch, 191 const std::string& default_if_unset, 192 base::Environment* environment, 193 CommandLine* command_line) { 194 std::string key_value = baked_in_value; 195 std::string temp; 196 if (environment->GetVar(environment_variable_name, &temp)) { 197 key_value = temp; 198 VLOG(1) << "Overriding API key " << environment_variable_name 199 << " with value " << key_value << " from environment variable."; 200 } 201 202 if (command_line_switch && command_line->HasSwitch(command_line_switch)) { 203 key_value = command_line->GetSwitchValueASCII(command_line_switch); 204 VLOG(1) << "Overriding API key " << environment_variable_name 205 << " with value " << key_value << " from command-line switch."; 206 } 207 208 if (key_value == DUMMY_API_TOKEN) { 209 #if defined(GOOGLE_CHROME_BUILD) 210 // No key should be unset in an official build except the 211 // GOOGLE_DEFAULT_* keys. The default keys don't trigger this 212 // check as their "unset" value is not DUMMY_API_TOKEN. 213 CHECK(false); 214 #endif 215 if (default_if_unset.size() > 0) { 216 VLOG(1) << "Using default value \"" << default_if_unset 217 << "\" for API key " << environment_variable_name; 218 key_value = default_if_unset; 219 } 220 } 221 222 // This should remain a debug-only log. 223 DVLOG(1) << "API key " << environment_variable_name << "=" << key_value; 224 225 return key_value; 226 } 227 228 std::string api_key_; 229 std::string client_ids_[CLIENT_NUM_ITEMS]; 230 std::string client_secrets_[CLIENT_NUM_ITEMS]; 231 }; 232 233 static base::LazyInstance<APIKeyCache> g_api_key_cache = 234 LAZY_INSTANCE_INITIALIZER; 235 236 bool HasKeysConfigured() { 237 if (GetAPIKey() == DUMMY_API_TOKEN) 238 return false; 239 240 for (size_t client_id = 0; client_id < CLIENT_NUM_ITEMS; ++client_id) { 241 OAuth2Client client = static_cast<OAuth2Client>(client_id); 242 if (GetOAuth2ClientID(client) == DUMMY_API_TOKEN || 243 GetOAuth2ClientSecret(client) == DUMMY_API_TOKEN) { 244 return false; 245 } 246 } 247 248 return true; 249 } 250 251 std::string GetAPIKey() { 252 return g_api_key_cache.Get().api_key(); 253 } 254 255 std::string GetOAuth2ClientID(OAuth2Client client) { 256 return g_api_key_cache.Get().GetClientID(client); 257 } 258 259 std::string GetOAuth2ClientSecret(OAuth2Client client) { 260 return g_api_key_cache.Get().GetClientSecret(client); 261 } 262 263 bool IsGoogleChromeAPIKeyUsed() { 264 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_OFFICIAL_GOOGLE_API_KEYS) 265 return true; 266 #else 267 return false; 268 #endif 269 } 270 271 } // namespace google_apis 272