• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
APIKeyCache()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 
api_key() const180   std::string api_key() const { return api_key_; }
181 
GetClientID(OAuth2Client client) const182   std::string GetClientID(OAuth2Client client) const {
183     DCHECK_LT(client, CLIENT_NUM_ITEMS);
184     return client_ids_[client];
185   }
186 
GetClientSecret(OAuth2Client client) const187   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.
CalculateKeyValue(const char * baked_in_value,const char * environment_variable_name,const char * command_line_switch,const std::string & default_if_unset,base::Environment * environment,CommandLine * command_line)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 
HasKeysConfigured()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 
GetAPIKey()260 std::string GetAPIKey() {
261   return g_api_key_cache.Get().api_key();
262 }
263 
GetOAuth2ClientID(OAuth2Client client)264 std::string GetOAuth2ClientID(OAuth2Client client) {
265   return g_api_key_cache.Get().GetClientID(client);
266 }
267 
GetOAuth2ClientSecret(OAuth2Client client)268 std::string GetOAuth2ClientSecret(OAuth2Client client) {
269   return g_api_key_cache.Get().GetClientSecret(client);
270 }
271 
272 }  // namespace google_apis
273