Home | History | Annotate | Download | only in google_apis
      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