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