Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1115)

Side by Side Diff: chrome/common/net/gaia/oauth_request_signer.cc

Issue 10928017: Moving google_apis and GaiaClient to src/google_apis. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge to head Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "chrome/common/net/gaia/oauth_request_signer.h"
6
7 #include <cctype>
8 #include <cstddef>
9 #include <cstdlib>
10 #include <cstring>
11 #include <ctime>
12 #include <map>
13 #include <string>
14
15 #include "base/base64.h"
16 #include "base/format_macros.h"
17 #include "base/logging.h"
18 #include "base/rand_util.h"
19 #include "base/string_util.h"
20 #include "base/stringprintf.h"
21 #include "base/time.h"
22 #include "crypto/hmac.h"
23 #include "googleurl/src/gurl.h"
24
25 namespace {
26
27 static const int kHexBase = 16;
28 static char kHexDigits[] = "0123456789ABCDEF";
29 static const size_t kHmacDigestLength = 20;
30 static const int kMaxNonceLength = 30;
31 static const int kMinNonceLength = 15;
32
33 static const char kOAuthConsumerKeyLabel[] = "oauth_consumer_key";
34 static const char kOAuthConsumerSecretLabel[] = "oauth_consumer_secret";
35 static const char kOAuthNonceCharacters[] =
36 "abcdefghijklmnopqrstuvwyz"
37 "ABCDEFGHIJKLMNOPQRSTUVWYZ"
38 "0123456789_";
39 static const char kOAuthNonceLabel[] = "oauth_nonce";
40 static const char kOAuthSignatureLabel[] = "oauth_signature";
41 static const char kOAuthSignatureMethodLabel[] = "oauth_signature_method";
42 static const char kOAuthTimestampLabel[] = "oauth_timestamp";
43 static const char kOAuthTokenLabel[] = "oauth_token";
44 static const char kOAuthTokenSecretLabel[] = "oauth_token_secret";
45 static const char kOAuthVersion[] = "1.0";
46 static const char kOAuthVersionLabel[] = "oauth_version";
47
48 enum ParseQueryState {
49 START_STATE,
50 KEYWORD_STATE,
51 VALUE_STATE,
52 };
53
54 const std::string HttpMethodName(OAuthRequestSigner::HttpMethod method) {
55 switch (method) {
56 case OAuthRequestSigner::GET_METHOD:
57 return "GET";
58 case OAuthRequestSigner::POST_METHOD:
59 return "POST";
60 }
61 NOTREACHED();
62 return *(new std::string());
63 }
64
65 const std::string SignatureMethodName(
66 OAuthRequestSigner::SignatureMethod method) {
67 switch (method) {
68 case OAuthRequestSigner::HMAC_SHA1_SIGNATURE:
69 return "HMAC-SHA1";
70 case OAuthRequestSigner::RSA_SHA1_SIGNATURE:
71 return "RSA-SHA1";
72 case OAuthRequestSigner::PLAINTEXT_SIGNATURE:
73 return "PLAINTEXT";
74 }
75 NOTREACHED();
76 return *(new std::string());
77 }
78
79 std::string BuildBaseString(const GURL& request_base_url,
80 OAuthRequestSigner::HttpMethod http_method,
81 const std::string& base_parameters) {
82 return StringPrintf("%s&%s&%s",
83 HttpMethodName(http_method).c_str(),
84 OAuthRequestSigner::Encode(
85 request_base_url.spec()).c_str(),
86 OAuthRequestSigner::Encode(
87 base_parameters).c_str());
88 }
89
90 std::string BuildBaseStringParameters(
91 const OAuthRequestSigner::Parameters& parameters) {
92 std::string result = "";
93 OAuthRequestSigner::Parameters::const_iterator cursor;
94 OAuthRequestSigner::Parameters::const_iterator limit;
95 bool first = true;
96 for (cursor = parameters.begin(), limit = parameters.end();
97 cursor != limit;
98 ++cursor) {
99 if (first)
100 first = false;
101 else
102 result += '&';
103 result += OAuthRequestSigner::Encode(cursor->first);
104 result += '=';
105 result += OAuthRequestSigner::Encode(cursor->second);
106 }
107 return result;
108 }
109
110 std::string GenerateNonce() {
111 char result[kMaxNonceLength + 1];
112 int length = base::RandUint64() % (kMaxNonceLength - kMinNonceLength + 1) +
113 kMinNonceLength;
114 result[length] = '\0';
115 for (int index = 0; index < length; ++index)
116 result[index] = kOAuthNonceCharacters[
117 base::RandUint64() % (sizeof(kOAuthNonceCharacters) - 1)];
118 return result;
119 }
120
121 std::string GenerateTimestamp() {
122 return base::StringPrintf(
123 "%" PRId64,
124 (base::Time::NowFromSystemTime() - base::Time::UnixEpoch()).InSeconds());
125 }
126
127 // Creates a string-to-string, keyword-value map from a parameter/query string
128 // that uses ampersand (&) to seperate paris and equals (=) to seperate
129 // keyword from value.
130 bool ParseQuery(const std::string& query,
131 OAuthRequestSigner::Parameters* parameters_result) {
132 std::string::const_iterator cursor;
133 std::string keyword;
134 std::string::const_iterator limit;
135 OAuthRequestSigner::Parameters parameters;
136 ParseQueryState state;
137 std::string value;
138
139 state = START_STATE;
140 for (cursor = query.begin(), limit = query.end();
141 cursor != limit;
142 ++cursor) {
143 char character = *cursor;
144 switch (state) {
145 case KEYWORD_STATE:
146 switch (character) {
147 case '&':
148 parameters[keyword] = value;
149 keyword = "";
150 value = "";
151 state = START_STATE;
152 break;
153 case '=':
154 state = VALUE_STATE;
155 break;
156 default:
157 keyword += character;
158 }
159 break;
160 case START_STATE:
161 switch (character) {
162 case '&': // Intentionally falling through
163 case '=':
164 return false;
165 default:
166 keyword += character;
167 state = KEYWORD_STATE;
168 }
169 break;
170 case VALUE_STATE:
171 switch (character) {
172 case '=':
173 return false;
174 case '&':
175 parameters[keyword] = value;
176 keyword = "";
177 value = "";
178 state = START_STATE;
179 break;
180 default:
181 value += character;
182 }
183 break;
184 }
185 }
186 switch (state) {
187 case START_STATE:
188 break;
189 case KEYWORD_STATE: // Intentionally falling through
190 case VALUE_STATE:
191 parameters[keyword] = value;
192 break;
193 default:
194 NOTREACHED();
195 }
196 *parameters_result = parameters;
197 return true;
198 }
199
200 // Creates the value for the oauth_signature parameter when the
201 // oauth_signature_method is HMAC-SHA1.
202 bool SignHmacSha1(const std::string& text,
203 const std::string& key,
204 std::string* signature_return) {
205 crypto::HMAC hmac(crypto::HMAC::SHA1);
206 DCHECK(hmac.DigestLength() == kHmacDigestLength);
207 unsigned char digest[kHmacDigestLength];
208 bool result = hmac.Init(key) &&
209 hmac.Sign(text, digest, kHmacDigestLength) &&
210 base::Base64Encode(std::string(reinterpret_cast<const char*>(digest),
211 kHmacDigestLength),
212 signature_return);
213 return result;
214 }
215
216 // Creates the value for the oauth_signature parameter when the
217 // oauth_signature_method is PLAINTEXT.
218 //
219 // Not yet implemented, and might never be.
220 bool SignPlaintext(const std::string& text,
221 const std::string& key,
222 std::string* result) {
223 NOTIMPLEMENTED();
224 return false;
225 }
226
227 // Creates the value for the oauth_signature parameter when the
228 // oauth_signature_method is RSA-SHA1.
229 //
230 // Not yet implemented, and might never be.
231 bool SignRsaSha1(const std::string& text,
232 const std::string& key,
233 std::string* result) {
234 NOTIMPLEMENTED();
235 return false;
236 }
237
238 // Adds parameters that are required by OAuth added as needed to |parameters|.
239 void PrepareParameters(OAuthRequestSigner::Parameters* parameters,
240 OAuthRequestSigner::SignatureMethod signature_method,
241 OAuthRequestSigner::HttpMethod http_method,
242 const std::string& consumer_key,
243 const std::string& token_key) {
244 if (parameters->find(kOAuthNonceLabel) == parameters->end())
245 (*parameters)[kOAuthNonceLabel] = GenerateNonce();
246
247 if (parameters->find(kOAuthTimestampLabel) == parameters->end())
248 (*parameters)[kOAuthTimestampLabel] = GenerateTimestamp();
249
250 (*parameters)[kOAuthConsumerKeyLabel] = consumer_key;
251 (*parameters)[kOAuthSignatureMethodLabel] =
252 SignatureMethodName(signature_method);
253 (*parameters)[kOAuthTokenLabel] = token_key;
254 (*parameters)[kOAuthVersionLabel] = kOAuthVersion;
255 }
256
257 // Implements shared signing logic, generating the signature and storing it in
258 // |parameters|. Returns true if the signature has been generated succesfully.
259 bool SignParameters(const GURL& request_base_url,
260 OAuthRequestSigner::SignatureMethod signature_method,
261 OAuthRequestSigner::HttpMethod http_method,
262 const std::string& consumer_key,
263 const std::string& consumer_secret,
264 const std::string& token_key,
265 const std::string& token_secret,
266 OAuthRequestSigner::Parameters* parameters) {
267 DCHECK(request_base_url.is_valid());
268 PrepareParameters(parameters, signature_method, http_method,
269 consumer_key, token_key);
270 std::string base_parameters = BuildBaseStringParameters(*parameters);
271 std::string base = BuildBaseString(request_base_url, http_method,
272 base_parameters);
273 std::string key = consumer_secret + '&' + token_secret;
274 bool is_signed = false;
275 std::string signature;
276 switch (signature_method) {
277 case OAuthRequestSigner::HMAC_SHA1_SIGNATURE:
278 is_signed = SignHmacSha1(base, key, &signature);
279 break;
280 case OAuthRequestSigner::RSA_SHA1_SIGNATURE:
281 is_signed = SignRsaSha1(base, key, &signature);
282 break;
283 case OAuthRequestSigner::PLAINTEXT_SIGNATURE:
284 is_signed = SignPlaintext(base, key, &signature);
285 break;
286 default:
287 NOTREACHED();
288 }
289 if (is_signed)
290 (*parameters)[kOAuthSignatureLabel] = signature;
291 return is_signed;
292 }
293
294
295 } // namespace
296
297 // static
298 bool OAuthRequestSigner::Decode(const std::string& text,
299 std::string* decoded_text) {
300 std::string accumulator = "";
301 std::string::const_iterator cursor;
302 std::string::const_iterator limit;
303 for (limit = text.end(), cursor = text.begin(); cursor != limit; ++cursor) {
304 char character = *cursor;
305 if (character == '%') {
306 ++cursor;
307 if (cursor == limit)
308 return false;
309 char* first = strchr(kHexDigits, *cursor);
310 if (!first)
311 return false;
312 int high = first - kHexDigits;
313 DCHECK(high >= 0 && high < kHexBase);
314
315 ++cursor;
316 if (cursor == limit)
317 return false;
318 char* second = strchr(kHexDigits, *cursor);
319 if (!second)
320 return false;
321 int low = second - kHexDigits;
322 DCHECK(low >= 0 || low < kHexBase);
323
324 char decoded = static_cast<char>(high * kHexBase + low);
325 DCHECK(!(IsAsciiAlpha(decoded) || IsAsciiDigit(decoded)));
326 DCHECK(!(decoded && strchr("-._~", decoded)));
327 accumulator += decoded;
328 } else {
329 accumulator += character;
330 }
331 }
332 *decoded_text = accumulator;
333 return true;
334 }
335
336 // static
337 std::string OAuthRequestSigner::Encode(const std::string& text) {
338 std::string result = "";
339 std::string::const_iterator cursor;
340 std::string::const_iterator limit;
341 for (limit = text.end(), cursor = text.begin(); cursor != limit; ++cursor) {
342 char character = *cursor;
343 if (IsAsciiAlpha(character) || IsAsciiDigit(character)) {
344 result += character;
345 } else {
346 switch (character) {
347 case '-':
348 case '.':
349 case '_':
350 case '~':
351 result += character;
352 break;
353 default:
354 unsigned char byte = static_cast<unsigned char>(character);
355 result = result + '%' + kHexDigits[byte / kHexBase] +
356 kHexDigits[byte % kHexBase];
357 }
358 }
359 }
360 return result;
361 }
362
363 // static
364 bool OAuthRequestSigner::ParseAndSign(const GURL& request_url_with_parameters,
365 SignatureMethod signature_method,
366 HttpMethod http_method,
367 const std::string& consumer_key,
368 const std::string& consumer_secret,
369 const std::string& token_key,
370 const std::string& token_secret,
371 std::string* result) {
372 DCHECK(request_url_with_parameters.is_valid());
373 Parameters parameters;
374 if (request_url_with_parameters.has_query()) {
375 const std::string& query = request_url_with_parameters.query();
376 if (!query.empty()) {
377 if (!ParseQuery(query, &parameters))
378 return false;
379 }
380 }
381 std::string spec = request_url_with_parameters.spec();
382 std::string url_without_parameters = spec;
383 std::string::size_type question = spec.find("?");
384 if (question != std::string::npos)
385 url_without_parameters = spec.substr(0,question);
386 return SignURL(GURL(url_without_parameters), parameters, signature_method,
387 http_method, consumer_key, consumer_secret, token_key,
388 token_secret, result);
389 }
390
391 // static
392 bool OAuthRequestSigner::SignURL(
393 const GURL& request_base_url,
394 const Parameters& request_parameters,
395 SignatureMethod signature_method,
396 HttpMethod http_method,
397 const std::string& consumer_key,
398 const std::string& consumer_secret,
399 const std::string& token_key,
400 const std::string& token_secret,
401 std::string* signed_text_return) {
402 DCHECK(request_base_url.is_valid());
403 Parameters parameters(request_parameters);
404 bool is_signed = SignParameters(request_base_url, signature_method,
405 http_method, consumer_key, consumer_secret,
406 token_key, token_secret, &parameters);
407 if (is_signed) {
408 std::string signed_text;
409 switch (http_method) {
410 case GET_METHOD:
411 signed_text = request_base_url.spec() + '?';
412 // Intentionally falling through
413 case POST_METHOD:
414 signed_text += BuildBaseStringParameters(parameters);
415 break;
416 default:
417 NOTREACHED();
418 }
419 *signed_text_return = signed_text;
420 }
421 return is_signed;
422 }
423
424 // static
425 bool OAuthRequestSigner::SignAuthHeader(
426 const GURL& request_base_url,
427 const Parameters& request_parameters,
428 SignatureMethod signature_method,
429 HttpMethod http_method,
430 const std::string& consumer_key,
431 const std::string& consumer_secret,
432 const std::string& token_key,
433 const std::string& token_secret,
434 std::string* signed_text_return) {
435 DCHECK(request_base_url.is_valid());
436 Parameters parameters(request_parameters);
437 bool is_signed = SignParameters(request_base_url, signature_method,
438 http_method, consumer_key, consumer_secret,
439 token_key, token_secret, &parameters);
440 if (is_signed) {
441 std::string signed_text = "OAuth ";
442 bool first = true;
443 for (Parameters::const_iterator param = parameters.begin();
444 param != parameters.end();
445 ++param) {
446 if (first)
447 first = false;
448 else
449 signed_text += ", ";
450 signed_text +=
451 StringPrintf("%s=\"%s\"",
452 OAuthRequestSigner::Encode(param->first).c_str(),
453 OAuthRequestSigner::Encode(param->second).c_str());
454 }
455 *signed_text_return = signed_text;
456 }
457 return is_signed;
458 }
OLDNEW
« no previous file with comments | « chrome/common/net/gaia/oauth_request_signer.h ('k') | chrome/common/net/gaia/oauth_request_signer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698