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