OLD | NEW |
| (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/gaia_auth_fetcher.h" | |
6 | |
7 #include <algorithm> | |
8 #include <string> | |
9 #include <utility> | |
10 #include <vector> | |
11 | |
12 #include "base/json/json_reader.h" | |
13 #include "base/json/json_writer.h" | |
14 #include "base/string_split.h" | |
15 #include "base/string_util.h" | |
16 #include "base/stringprintf.h" | |
17 #include "base/values.h" | |
18 #include "chrome/common/net/gaia/gaia_auth_consumer.h" | |
19 #include "chrome/common/net/gaia/gaia_constants.h" | |
20 #include "chrome/common/net/gaia/gaia_urls.h" | |
21 #include "chrome/common/net/gaia/google_service_auth_error.h" | |
22 #include "net/base/escape.h" | |
23 #include "net/base/load_flags.h" | |
24 #include "net/http/http_status_code.h" | |
25 #include "net/url_request/url_fetcher.h" | |
26 #include "net/url_request/url_request_context_getter.h" | |
27 #include "net/url_request/url_request_status.h" | |
28 | |
29 namespace { | |
30 const int kLoadFlagsIgnoreCookies = net::LOAD_DO_NOT_SEND_COOKIES | | |
31 net::LOAD_DO_NOT_SAVE_COOKIES; | |
32 | |
33 static bool CookiePartsContains(const std::vector<std::string>& parts, | |
34 const char* part) { | |
35 return std::find(parts.begin(), parts.end(), part) != parts.end(); | |
36 } | |
37 | |
38 bool ExtractOAuth2TokenPairResponse(DictionaryValue* dict, | |
39 std::string* refresh_token, | |
40 std::string* access_token, | |
41 int* expires_in_secs) { | |
42 DCHECK(refresh_token); | |
43 DCHECK(access_token); | |
44 DCHECK(expires_in_secs); | |
45 | |
46 if (!dict->GetStringWithoutPathExpansion("refresh_token", refresh_token) || | |
47 !dict->GetStringWithoutPathExpansion("access_token", access_token) || | |
48 !dict->GetIntegerWithoutPathExpansion("expires_in", expires_in_secs)) { | |
49 return false; | |
50 } | |
51 | |
52 return true; | |
53 } | |
54 | |
55 } // namespace | |
56 | |
57 // TODO(chron): Add sourceless version of this formatter. | |
58 // static | |
59 const char GaiaAuthFetcher::kClientLoginFormat[] = | |
60 "Email=%s&" | |
61 "Passwd=%s&" | |
62 "PersistentCookie=%s&" | |
63 "accountType=%s&" | |
64 "source=%s&" | |
65 "service=%s"; | |
66 // static | |
67 const char GaiaAuthFetcher::kClientLoginCaptchaFormat[] = | |
68 "Email=%s&" | |
69 "Passwd=%s&" | |
70 "PersistentCookie=%s&" | |
71 "accountType=%s&" | |
72 "source=%s&" | |
73 "service=%s&" | |
74 "logintoken=%s&" | |
75 "logincaptcha=%s"; | |
76 // static | |
77 const char GaiaAuthFetcher::kIssueAuthTokenFormat[] = | |
78 "SID=%s&" | |
79 "LSID=%s&" | |
80 "service=%s&" | |
81 "Session=%s"; | |
82 // static | |
83 const char GaiaAuthFetcher::kClientLoginToOAuth2BodyFormat[] = | |
84 "scope=%s&client_id=%s"; | |
85 // static | |
86 const char GaiaAuthFetcher::kOAuth2CodeToTokenPairBodyFormat[] = | |
87 "scope=%s&" | |
88 "grant_type=authorization_code&" | |
89 "client_id=%s&" | |
90 "client_secret=%s&" | |
91 "code=%s"; | |
92 // static | |
93 const char GaiaAuthFetcher::kGetUserInfoFormat[] = | |
94 "LSID=%s"; | |
95 // static | |
96 const char GaiaAuthFetcher::kMergeSessionFormat[] = | |
97 "uberauth=%s&" | |
98 "continue=%s&" | |
99 "source=%s"; | |
100 // static | |
101 const char GaiaAuthFetcher::kUberAuthTokenURLFormat[] = | |
102 "%s?source=%s&" | |
103 "issueuberauth=1"; | |
104 | |
105 const char GaiaAuthFetcher::kOAuthLoginFormat[] = "service=%s&source=%s"; | |
106 | |
107 // static | |
108 const char GaiaAuthFetcher::kAccountDeletedError[] = "AccountDeleted"; | |
109 const char GaiaAuthFetcher::kAccountDeletedErrorCode[] = "adel"; | |
110 // static | |
111 const char GaiaAuthFetcher::kAccountDisabledError[] = "AccountDisabled"; | |
112 const char GaiaAuthFetcher::kAccountDisabledErrorCode[] = "adis"; | |
113 // static | |
114 const char GaiaAuthFetcher::kBadAuthenticationError[] = "BadAuthentication"; | |
115 const char GaiaAuthFetcher::kBadAuthenticationErrorCode[] = "badauth"; | |
116 // static | |
117 const char GaiaAuthFetcher::kCaptchaError[] = "CaptchaRequired"; | |
118 const char GaiaAuthFetcher::kCaptchaErrorCode[] = "cr"; | |
119 // static | |
120 const char GaiaAuthFetcher::kServiceUnavailableError[] = | |
121 "ServiceUnavailable"; | |
122 const char GaiaAuthFetcher::kServiceUnavailableErrorCode[] = | |
123 "ire"; | |
124 // static | |
125 const char GaiaAuthFetcher::kErrorParam[] = "Error"; | |
126 // static | |
127 const char GaiaAuthFetcher::kErrorUrlParam[] = "Url"; | |
128 // static | |
129 const char GaiaAuthFetcher::kCaptchaUrlParam[] = "CaptchaUrl"; | |
130 // static | |
131 const char GaiaAuthFetcher::kCaptchaTokenParam[] = "CaptchaToken"; | |
132 | |
133 // static | |
134 const char GaiaAuthFetcher::kNeedsAdditional[] = "NeedsAdditional"; | |
135 // static | |
136 const char GaiaAuthFetcher::kCaptcha[] = "Captcha"; | |
137 // static | |
138 const char GaiaAuthFetcher::kTwoFactor[] = "TwoStep"; | |
139 | |
140 // static | |
141 const char GaiaAuthFetcher::kCookiePersistence[] = "true"; | |
142 // static | |
143 // TODO(johnnyg): When hosted accounts are supported by sync, | |
144 // we can always use "HOSTED_OR_GOOGLE" | |
145 const char GaiaAuthFetcher::kAccountTypeHostedOrGoogle[] = | |
146 "HOSTED_OR_GOOGLE"; | |
147 const char GaiaAuthFetcher::kAccountTypeGoogle[] = | |
148 "GOOGLE"; | |
149 | |
150 // static | |
151 const char GaiaAuthFetcher::kSecondFactor[] = "Info=InvalidSecondFactor"; | |
152 | |
153 // static | |
154 const char GaiaAuthFetcher::kAuthHeaderFormat[] = | |
155 "Authorization: GoogleLogin auth=%s"; | |
156 // static | |
157 const char GaiaAuthFetcher::kOAuthHeaderFormat[] = "Authorization: OAuth %s"; | |
158 // static | |
159 const char GaiaAuthFetcher::kClientLoginToOAuth2CookiePartSecure[] = "Secure"; | |
160 // static | |
161 const char GaiaAuthFetcher::kClientLoginToOAuth2CookiePartHttpOnly[] = | |
162 "HttpOnly"; | |
163 // static | |
164 const char GaiaAuthFetcher::kClientLoginToOAuth2CookiePartCodePrefix[] = | |
165 "oauth_code="; | |
166 // static | |
167 const int GaiaAuthFetcher::kClientLoginToOAuth2CookiePartCodePrefixLength = | |
168 arraysize(GaiaAuthFetcher::kClientLoginToOAuth2CookiePartCodePrefix) - 1; | |
169 | |
170 GaiaAuthFetcher::GaiaAuthFetcher(GaiaAuthConsumer* consumer, | |
171 const std::string& source, | |
172 net::URLRequestContextGetter* getter) | |
173 : consumer_(consumer), | |
174 getter_(getter), | |
175 source_(source), | |
176 client_login_gurl_(GaiaUrls::GetInstance()->client_login_url()), | |
177 issue_auth_token_gurl_(GaiaUrls::GetInstance()->issue_auth_token_url()), | |
178 oauth2_token_gurl_(GaiaUrls::GetInstance()->oauth2_token_url()), | |
179 get_user_info_gurl_(GaiaUrls::GetInstance()->get_user_info_url()), | |
180 merge_session_gurl_(GaiaUrls::GetInstance()->merge_session_url()), | |
181 uberauth_token_gurl_(base::StringPrintf(kUberAuthTokenURLFormat, | |
182 GaiaUrls::GetInstance()->oauth1_login_url().c_str(), source.c_str())), | |
183 client_oauth_gurl_(GaiaUrls::GetInstance()->client_oauth_url()), | |
184 oauth_login_gurl_(GaiaUrls::GetInstance()->oauth1_login_url()), | |
185 client_login_to_oauth2_gurl_( | |
186 GaiaUrls::GetInstance()->client_login_to_oauth2_url()), | |
187 fetch_pending_(false) {} | |
188 | |
189 GaiaAuthFetcher::~GaiaAuthFetcher() {} | |
190 | |
191 bool GaiaAuthFetcher::HasPendingFetch() { | |
192 return fetch_pending_; | |
193 } | |
194 | |
195 void GaiaAuthFetcher::CancelRequest() { | |
196 fetcher_.reset(); | |
197 fetch_pending_ = false; | |
198 } | |
199 | |
200 // static | |
201 net::URLFetcher* GaiaAuthFetcher::CreateGaiaFetcher( | |
202 net::URLRequestContextGetter* getter, | |
203 const std::string& body, | |
204 const std::string& headers, | |
205 const GURL& gaia_gurl, | |
206 int load_flags, | |
207 net::URLFetcherDelegate* delegate) { | |
208 net::URLFetcher* to_return = net::URLFetcher::Create( | |
209 0, gaia_gurl, | |
210 body == "" ? net::URLFetcher::GET : net::URLFetcher::POST, | |
211 delegate); | |
212 to_return->SetRequestContext(getter); | |
213 to_return->SetUploadData("application/x-www-form-urlencoded", body); | |
214 | |
215 DVLOG(2) << "Gaia fetcher URL: " << gaia_gurl.spec(); | |
216 DVLOG(2) << "Gaia fetcher headers: " << headers; | |
217 DVLOG(2) << "Gaia fetcher body: " << body; | |
218 | |
219 // The Gaia token exchange requests do not require any cookie-based | |
220 // identification as part of requests. We suppress sending any cookies to | |
221 // maintain a separation between the user's browsing and Chrome's internal | |
222 // services. Where such mixing is desired (MergeSession), it will be done | |
223 // explicitly. | |
224 to_return->SetLoadFlags(load_flags); | |
225 | |
226 if (!headers.empty()) | |
227 to_return->SetExtraRequestHeaders(headers); | |
228 | |
229 return to_return; | |
230 } | |
231 | |
232 // static | |
233 std::string GaiaAuthFetcher::MakeClientLoginBody( | |
234 const std::string& username, | |
235 const std::string& password, | |
236 const std::string& source, | |
237 const char* service, | |
238 const std::string& login_token, | |
239 const std::string& login_captcha, | |
240 HostedAccountsSetting allow_hosted_accounts) { | |
241 std::string encoded_username = net::EscapeUrlEncodedData(username, true); | |
242 std::string encoded_password = net::EscapeUrlEncodedData(password, true); | |
243 std::string encoded_login_token = net::EscapeUrlEncodedData(login_token, | |
244 true); | |
245 std::string encoded_login_captcha = net::EscapeUrlEncodedData(login_captcha, | |
246 true); | |
247 | |
248 const char* account_type = allow_hosted_accounts == HostedAccountsAllowed ? | |
249 kAccountTypeHostedOrGoogle : | |
250 kAccountTypeGoogle; | |
251 | |
252 if (login_token.empty() || login_captcha.empty()) { | |
253 return base::StringPrintf(kClientLoginFormat, | |
254 encoded_username.c_str(), | |
255 encoded_password.c_str(), | |
256 kCookiePersistence, | |
257 account_type, | |
258 source.c_str(), | |
259 service); | |
260 } | |
261 | |
262 return base::StringPrintf(kClientLoginCaptchaFormat, | |
263 encoded_username.c_str(), | |
264 encoded_password.c_str(), | |
265 kCookiePersistence, | |
266 account_type, | |
267 source.c_str(), | |
268 service, | |
269 encoded_login_token.c_str(), | |
270 encoded_login_captcha.c_str()); | |
271 } | |
272 | |
273 // static | |
274 std::string GaiaAuthFetcher::MakeIssueAuthTokenBody( | |
275 const std::string& sid, | |
276 const std::string& lsid, | |
277 const char* const service) { | |
278 std::string encoded_sid = net::EscapeUrlEncodedData(sid, true); | |
279 std::string encoded_lsid = net::EscapeUrlEncodedData(lsid, true); | |
280 | |
281 // All tokens should be session tokens except the gaia auth token. | |
282 bool session = true; | |
283 if (!strcmp(service, GaiaConstants::kGaiaService)) | |
284 session = false; | |
285 | |
286 return base::StringPrintf(kIssueAuthTokenFormat, | |
287 encoded_sid.c_str(), | |
288 encoded_lsid.c_str(), | |
289 service, | |
290 session ? "true" : "false"); | |
291 } | |
292 | |
293 // static | |
294 std::string GaiaAuthFetcher::MakeGetAuthCodeBody() { | |
295 std::string encoded_scope = net::EscapeUrlEncodedData( | |
296 GaiaUrls::GetInstance()->oauth1_login_scope(), true); | |
297 std::string encoded_client_id = net::EscapeUrlEncodedData( | |
298 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true); | |
299 return StringPrintf(kClientLoginToOAuth2BodyFormat, | |
300 encoded_scope.c_str(), | |
301 encoded_client_id.c_str()); | |
302 } | |
303 | |
304 // static | |
305 std::string GaiaAuthFetcher::MakeGetTokenPairBody( | |
306 const std::string& auth_code) { | |
307 std::string encoded_scope = net::EscapeUrlEncodedData( | |
308 GaiaUrls::GetInstance()->oauth1_login_scope(), true); | |
309 std::string encoded_client_id = net::EscapeUrlEncodedData( | |
310 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true); | |
311 std::string encoded_client_secret = net::EscapeUrlEncodedData( | |
312 GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), true); | |
313 std::string encoded_auth_code = net::EscapeUrlEncodedData(auth_code, true); | |
314 return StringPrintf(kOAuth2CodeToTokenPairBodyFormat, | |
315 encoded_scope.c_str(), | |
316 encoded_client_id.c_str(), | |
317 encoded_client_secret.c_str(), | |
318 encoded_auth_code.c_str()); | |
319 } | |
320 | |
321 // static | |
322 std::string GaiaAuthFetcher::MakeGetUserInfoBody(const std::string& lsid) { | |
323 std::string encoded_lsid = net::EscapeUrlEncodedData(lsid, true); | |
324 return base::StringPrintf(kGetUserInfoFormat, encoded_lsid.c_str()); | |
325 } | |
326 | |
327 // static | |
328 std::string GaiaAuthFetcher::MakeMergeSessionBody( | |
329 const std::string& auth_token, | |
330 const std::string& continue_url, | |
331 const std::string& source) { | |
332 std::string encoded_auth_token = net::EscapeUrlEncodedData(auth_token, true); | |
333 std::string encoded_continue_url = net::EscapeUrlEncodedData(continue_url, | |
334 true); | |
335 std::string encoded_source = net::EscapeUrlEncodedData(source, true); | |
336 return base::StringPrintf(kMergeSessionFormat, | |
337 encoded_auth_token.c_str(), | |
338 encoded_continue_url.c_str(), | |
339 encoded_source.c_str()); | |
340 } | |
341 | |
342 // static | |
343 std::string GaiaAuthFetcher::MakeGetAuthCodeHeader( | |
344 const std::string& auth_token) { | |
345 return StringPrintf(kAuthHeaderFormat, auth_token.c_str()); | |
346 } | |
347 | |
348 // Helper method that extracts tokens from a successful reply. | |
349 // static | |
350 void GaiaAuthFetcher::ParseClientLoginResponse(const std::string& data, | |
351 std::string* sid, | |
352 std::string* lsid, | |
353 std::string* token) { | |
354 using std::vector; | |
355 using std::pair; | |
356 using std::string; | |
357 | |
358 vector<pair<string, string> > tokens; | |
359 base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens); | |
360 for (vector<pair<string, string> >::iterator i = tokens.begin(); | |
361 i != tokens.end(); ++i) { | |
362 if (i->first == "SID") { | |
363 sid->assign(i->second); | |
364 } else if (i->first == "LSID") { | |
365 lsid->assign(i->second); | |
366 } else if (i->first == "Auth") { | |
367 token->assign(i->second); | |
368 } | |
369 } | |
370 } | |
371 | |
372 // static | |
373 std::string GaiaAuthFetcher::MakeClientOAuthBody( | |
374 const std::string& username, | |
375 const std::string& password, | |
376 const std::vector<std::string>& scopes, | |
377 const std::string& persistent_id, | |
378 const std::string& friendly_name, | |
379 const std::string& locale) { | |
380 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue); | |
381 dict->SetString(GaiaConstants::kClientOAuthEmailKey, username); | |
382 dict->SetString(GaiaConstants::kClientOAuthPasswordKey, password); | |
383 | |
384 scoped_ptr<base::ListValue> scope_list(new base::ListValue); | |
385 for (size_t i = 0; i < scopes.size(); ++i) | |
386 scope_list->Append(base::Value::CreateStringValue(scopes[i])); | |
387 dict->Set(GaiaConstants::kClientOAuthScopesKey, scope_list.release()); | |
388 | |
389 dict->SetString(GaiaConstants::kClientOAuthOAuth2ClientIdKey, | |
390 GaiaUrls::GetInstance()->oauth2_chrome_client_id()); | |
391 // crbug.com/129600: use a less generic friendly name. | |
392 dict->SetString(GaiaConstants::kClientOAuthFriendlyDeviceNameKey, | |
393 friendly_name); | |
394 | |
395 scoped_ptr<base::ListValue> accepts_challenge_list(new base::ListValue); | |
396 accepts_challenge_list->Append(base::Value::CreateStringValue(kCaptcha)); | |
397 accepts_challenge_list->Append(base::Value::CreateStringValue(kTwoFactor)); | |
398 dict->Set(GaiaConstants::kClientOAuthAcceptsChallengesKey, | |
399 accepts_challenge_list.release()); | |
400 | |
401 dict->SetString(GaiaConstants::kClientOAuthLocaleKey, locale); | |
402 // Chrome presently does not not support a web-fallback for ClientOAuth, | |
403 // but need to hardcode an arbitrary one here since the endpoint expects it. | |
404 dict->SetString(GaiaConstants::kClientOAuthFallbackNameKey, "GetOAuth2Token"); | |
405 | |
406 std::string json_string; | |
407 base::JSONWriter::Write(dict.get(), &json_string); | |
408 return json_string; | |
409 } | |
410 | |
411 // static | |
412 std::string GaiaAuthFetcher::MakeClientOAuthChallengeResponseBody( | |
413 const std::string& name, | |
414 const std::string& token, | |
415 const std::string& solution) { | |
416 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue); | |
417 std::string field_name = name == kTwoFactor ? "otp" : "solution"; | |
418 | |
419 scoped_ptr<base::DictionaryValue> challenge_reply(new base::DictionaryValue); | |
420 challenge_reply->SetString(GaiaConstants::kClientOAuthNameKey, name); | |
421 challenge_reply->SetString(GaiaConstants::kClientOAuthChallengeTokenKey, | |
422 token); | |
423 challenge_reply->SetString(field_name, solution); | |
424 dict->Set(GaiaConstants::kClientOAuthchallengeReplyKey, | |
425 challenge_reply.release()); | |
426 | |
427 std::string json_string; | |
428 base::JSONWriter::Write(dict.get(), &json_string); | |
429 return json_string; | |
430 } | |
431 | |
432 // static | |
433 std::string GaiaAuthFetcher::MakeOAuthLoginBody(const std::string& service, | |
434 const std::string& source) { | |
435 std::string encoded_service = net::EscapeUrlEncodedData(service, true); | |
436 std::string encoded_source = net::EscapeUrlEncodedData(source, true); | |
437 return StringPrintf(kOAuthLoginFormat, encoded_service.c_str(), | |
438 encoded_source.c_str()); | |
439 } | |
440 | |
441 // static | |
442 void GaiaAuthFetcher::ParseClientLoginFailure(const std::string& data, | |
443 std::string* error, | |
444 std::string* error_url, | |
445 std::string* captcha_url, | |
446 std::string* captcha_token) { | |
447 using std::vector; | |
448 using std::pair; | |
449 using std::string; | |
450 | |
451 vector<pair<string, string> > tokens; | |
452 base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens); | |
453 for (vector<pair<string, string> >::iterator i = tokens.begin(); | |
454 i != tokens.end(); ++i) { | |
455 if (i->first == kErrorParam) { | |
456 error->assign(i->second); | |
457 } else if (i->first == kErrorUrlParam) { | |
458 error_url->assign(i->second); | |
459 } else if (i->first == kCaptchaUrlParam) { | |
460 captcha_url->assign(i->second); | |
461 } else if (i->first == kCaptchaTokenParam) { | |
462 captcha_token->assign(i->second); | |
463 } | |
464 } | |
465 } | |
466 | |
467 // static | |
468 bool GaiaAuthFetcher::ParseClientLoginToOAuth2Response( | |
469 const net::ResponseCookies& cookies, | |
470 std::string* auth_code) { | |
471 DCHECK(auth_code); | |
472 net::ResponseCookies::const_iterator iter; | |
473 for (iter = cookies.begin(); iter != cookies.end(); ++iter) { | |
474 if (ParseClientLoginToOAuth2Cookie(*iter, auth_code)) | |
475 return true; | |
476 } | |
477 return false; | |
478 } | |
479 | |
480 // static | |
481 bool GaiaAuthFetcher::ParseClientLoginToOAuth2Cookie(const std::string& cookie, | |
482 std::string* auth_code) { | |
483 std::vector<std::string> parts; | |
484 base::SplitString(cookie, ';', &parts); | |
485 // Per documentation, the cookie should have Secure and HttpOnly. | |
486 if (!CookiePartsContains(parts, kClientLoginToOAuth2CookiePartSecure) || | |
487 !CookiePartsContains(parts, kClientLoginToOAuth2CookiePartHttpOnly)) { | |
488 return false; | |
489 } | |
490 | |
491 std::vector<std::string>::const_iterator iter; | |
492 for (iter = parts.begin(); iter != parts.end(); ++iter) { | |
493 const std::string& part = *iter; | |
494 if (StartsWithASCII( | |
495 part, kClientLoginToOAuth2CookiePartCodePrefix, false)) { | |
496 auth_code->assign(part.substr( | |
497 kClientLoginToOAuth2CookiePartCodePrefixLength)); | |
498 return true; | |
499 } | |
500 } | |
501 return false; | |
502 } | |
503 | |
504 // static | |
505 GoogleServiceAuthError | |
506 GaiaAuthFetcher::GenerateClientOAuthError(const std::string& data, | |
507 const net::URLRequestStatus& status) { | |
508 scoped_ptr<base::Value> value(base::JSONReader::Read(data)); | |
509 if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) | |
510 return GenerateAuthError(data, status); | |
511 DictionaryValue* dict = static_cast<DictionaryValue*>(value.get()); | |
512 | |
513 std::string cause; | |
514 if (!dict->GetStringWithoutPathExpansion("cause", &cause)) | |
515 return GoogleServiceAuthError::FromClientOAuthError(data); | |
516 | |
517 if (cause != kNeedsAdditional) | |
518 return GoogleServiceAuthError::FromClientOAuthError(data); | |
519 | |
520 DictionaryValue* challenge; | |
521 if (!dict->GetDictionaryWithoutPathExpansion("challenge", &challenge)) | |
522 return GoogleServiceAuthError::FromClientOAuthError(data); | |
523 | |
524 std::string name; | |
525 if (!challenge->GetStringWithoutPathExpansion("name", &name)) | |
526 return GoogleServiceAuthError::FromClientOAuthError(data); | |
527 | |
528 if (name == kCaptcha) { | |
529 std::string token; | |
530 std::string audio_url; | |
531 std::string image_url; | |
532 int image_width; | |
533 int image_height; | |
534 if (!challenge->GetStringWithoutPathExpansion("challenge_token", &token) || | |
535 !challenge->GetStringWithoutPathExpansion("audio_url", &audio_url) || | |
536 !challenge->GetStringWithoutPathExpansion("image_url", &image_url) || | |
537 !challenge->GetIntegerWithoutPathExpansion("image_width", | |
538 &image_width) || | |
539 !challenge->GetIntegerWithoutPathExpansion("image_height", | |
540 &image_height)) { | |
541 return GoogleServiceAuthError::FromClientOAuthError(data); | |
542 } | |
543 return GoogleServiceAuthError::FromCaptchaChallenge(token, GURL(audio_url), | |
544 GURL(image_url), | |
545 image_width, | |
546 image_height); | |
547 } else if (name == kTwoFactor) { | |
548 std::string token; | |
549 std::string prompt_text; | |
550 std::string alternate_text; | |
551 int field_length; | |
552 | |
553 // The protocol doc says these are required, but in practice they are not | |
554 // returned. So only a missing challenge token will cause an error here. | |
555 challenge->GetStringWithoutPathExpansion("prompt_text", &prompt_text); | |
556 challenge->GetStringWithoutPathExpansion("alternate_text", &alternate_text); | |
557 challenge->GetIntegerWithoutPathExpansion("field_length", &field_length); | |
558 if (!challenge->GetStringWithoutPathExpansion("challenge_token", &token)) | |
559 return GoogleServiceAuthError::FromClientOAuthError(data); | |
560 | |
561 return GoogleServiceAuthError::FromSecondFactorChallenge(token, prompt_text, | |
562 alternate_text, | |
563 field_length); | |
564 } | |
565 | |
566 return GoogleServiceAuthError::FromClientOAuthError(data); | |
567 } | |
568 | |
569 void GaiaAuthFetcher::StartClientLogin( | |
570 const std::string& username, | |
571 const std::string& password, | |
572 const char* const service, | |
573 const std::string& login_token, | |
574 const std::string& login_captcha, | |
575 HostedAccountsSetting allow_hosted_accounts) { | |
576 | |
577 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
578 | |
579 // This class is thread agnostic, so be sure to call this only on the | |
580 // same thread each time. | |
581 DVLOG(1) << "Starting new ClientLogin fetch for:" << username; | |
582 | |
583 // Must outlive fetcher_. | |
584 request_body_ = MakeClientLoginBody(username, | |
585 password, | |
586 source_, | |
587 service, | |
588 login_token, | |
589 login_captcha, | |
590 allow_hosted_accounts); | |
591 fetcher_.reset(CreateGaiaFetcher(getter_, | |
592 request_body_, | |
593 "", | |
594 client_login_gurl_, | |
595 kLoadFlagsIgnoreCookies, | |
596 this)); | |
597 fetch_pending_ = true; | |
598 fetcher_->Start(); | |
599 } | |
600 | |
601 void GaiaAuthFetcher::StartIssueAuthToken(const std::string& sid, | |
602 const std::string& lsid, | |
603 const char* const service) { | |
604 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
605 | |
606 DVLOG(1) << "Starting IssueAuthToken for: " << service; | |
607 requested_service_ = service; | |
608 request_body_ = MakeIssueAuthTokenBody(sid, lsid, service); | |
609 fetcher_.reset(CreateGaiaFetcher(getter_, | |
610 request_body_, | |
611 "", | |
612 issue_auth_token_gurl_, | |
613 kLoadFlagsIgnoreCookies, | |
614 this)); | |
615 fetch_pending_ = true; | |
616 fetcher_->Start(); | |
617 } | |
618 | |
619 void GaiaAuthFetcher::StartLsoForOAuthLoginTokenExchange( | |
620 const std::string& auth_token) { | |
621 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
622 | |
623 DVLOG(1) << "Starting OAuth login token exchange with auth_token"; | |
624 request_body_ = MakeGetAuthCodeBody(); | |
625 client_login_to_oauth2_gurl_ = | |
626 GURL(GaiaUrls::GetInstance()->client_login_to_oauth2_url()); | |
627 | |
628 fetcher_.reset(CreateGaiaFetcher(getter_, | |
629 request_body_, | |
630 MakeGetAuthCodeHeader(auth_token), | |
631 client_login_to_oauth2_gurl_, | |
632 kLoadFlagsIgnoreCookies, | |
633 this)); | |
634 fetch_pending_ = true; | |
635 fetcher_->Start(); | |
636 } | |
637 | |
638 void GaiaAuthFetcher::StartCookieForOAuthLoginTokenExchange( | |
639 const std::string& session_index) { | |
640 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
641 | |
642 DVLOG(1) << "Starting OAuth login token fetch with cookie jar"; | |
643 request_body_ = MakeGetAuthCodeBody(); | |
644 | |
645 std::string url = GaiaUrls::GetInstance()->client_login_to_oauth2_url(); | |
646 if (!session_index.empty()) | |
647 url += "?authuser=" + session_index; | |
648 | |
649 client_login_to_oauth2_gurl_ = GURL(url); | |
650 | |
651 fetcher_.reset(CreateGaiaFetcher(getter_, | |
652 request_body_, | |
653 "", | |
654 client_login_to_oauth2_gurl_, | |
655 net::LOAD_NORMAL, | |
656 this)); | |
657 fetch_pending_ = true; | |
658 fetcher_->Start(); | |
659 } | |
660 | |
661 void GaiaAuthFetcher::StartGetUserInfo(const std::string& lsid) { | |
662 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
663 | |
664 DVLOG(1) << "Starting GetUserInfo for lsid=" << lsid; | |
665 request_body_ = MakeGetUserInfoBody(lsid); | |
666 fetcher_.reset(CreateGaiaFetcher(getter_, | |
667 request_body_, | |
668 "", | |
669 get_user_info_gurl_, | |
670 kLoadFlagsIgnoreCookies, | |
671 this)); | |
672 fetch_pending_ = true; | |
673 fetcher_->Start(); | |
674 } | |
675 | |
676 void GaiaAuthFetcher::StartMergeSession(const std::string& uber_token) { | |
677 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
678 | |
679 DVLOG(1) << "Starting MergeSession with uber_token=" << uber_token; | |
680 | |
681 // The continue URL is a required parameter of the MergeSession API, but in | |
682 // this case we don't actually need or want to navigate to it. Setting it to | |
683 // an arbitrary Google URL. | |
684 // | |
685 // In order for the new session to be merged correctly, the server needs to | |
686 // know what sessions already exist in the browser. The fetcher needs to be | |
687 // created such that it sends the cookies with the request, which is | |
688 // different from all other requests the fetcher can make. | |
689 std::string continue_url("http://www.google.com"); | |
690 request_body_ = MakeMergeSessionBody(uber_token, continue_url, source_); | |
691 fetcher_.reset(CreateGaiaFetcher(getter_, | |
692 request_body_, | |
693 "", | |
694 merge_session_gurl_, | |
695 net::LOAD_NORMAL, | |
696 this)); | |
697 fetch_pending_ = true; | |
698 fetcher_->Start(); | |
699 } | |
700 | |
701 void GaiaAuthFetcher::StartTokenFetchForUberAuthExchange( | |
702 const std::string& access_token) { | |
703 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
704 | |
705 DVLOG(1) << "Starting StartTokenFetchForUberAuthExchange with access_token=" | |
706 << access_token; | |
707 std::string authentication_header = | |
708 base::StringPrintf(kOAuthHeaderFormat, access_token.c_str()); | |
709 fetcher_.reset(CreateGaiaFetcher(getter_, | |
710 "", | |
711 authentication_header, | |
712 uberauth_token_gurl_, | |
713 kLoadFlagsIgnoreCookies, | |
714 this)); | |
715 fetch_pending_ = true; | |
716 fetcher_->Start(); | |
717 } | |
718 | |
719 void GaiaAuthFetcher::StartClientOAuth(const std::string& username, | |
720 const std::string& password, | |
721 const std::vector<std::string>& scopes, | |
722 const std::string& persistent_id, | |
723 const std::string& locale) { | |
724 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
725 | |
726 request_body_ = MakeClientOAuthBody(username, password, scopes, persistent_id, | |
727 source_, locale); | |
728 fetcher_.reset(CreateGaiaFetcher(getter_, | |
729 request_body_, | |
730 "", | |
731 client_oauth_gurl_, | |
732 kLoadFlagsIgnoreCookies, | |
733 this)); | |
734 fetch_pending_ = true; | |
735 fetcher_->Start(); | |
736 } | |
737 | |
738 void GaiaAuthFetcher::StartClientOAuthChallengeResponse( | |
739 GoogleServiceAuthError::State type, | |
740 const std::string& token, | |
741 const std::string& solution) { | |
742 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
743 | |
744 std::string name; | |
745 switch (type) { | |
746 case GoogleServiceAuthError::CAPTCHA_REQUIRED: | |
747 name = kCaptcha; | |
748 break; | |
749 case GoogleServiceAuthError::TWO_FACTOR: | |
750 name = kTwoFactor; | |
751 break; | |
752 default: | |
753 NOTREACHED(); | |
754 } | |
755 | |
756 request_body_ = MakeClientOAuthChallengeResponseBody(name, token, solution); | |
757 fetcher_.reset(CreateGaiaFetcher(getter_, | |
758 request_body_, | |
759 "", | |
760 client_oauth_gurl_, | |
761 kLoadFlagsIgnoreCookies, | |
762 this)); | |
763 fetch_pending_ = true; | |
764 fetcher_->Start(); | |
765 } | |
766 | |
767 void GaiaAuthFetcher::StartOAuthLogin(const std::string& access_token, | |
768 const std::string& service) { | |
769 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
770 | |
771 request_body_ = MakeOAuthLoginBody(service, source_); | |
772 std::string authentication_header = | |
773 base::StringPrintf("Authorization: Bearer %s", access_token.c_str()); | |
774 fetcher_.reset(CreateGaiaFetcher(getter_, | |
775 request_body_, | |
776 authentication_header, | |
777 oauth_login_gurl_, | |
778 kLoadFlagsIgnoreCookies, | |
779 this)); | |
780 fetch_pending_ = true; | |
781 fetcher_->Start(); | |
782 } | |
783 | |
784 // static | |
785 GoogleServiceAuthError GaiaAuthFetcher::GenerateAuthError( | |
786 const std::string& data, | |
787 const net::URLRequestStatus& status) { | |
788 if (!status.is_success()) { | |
789 if (status.status() == net::URLRequestStatus::CANCELED) { | |
790 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED); | |
791 } else { | |
792 DLOG(WARNING) << "Could not reach Google Accounts servers: errno " | |
793 << status.error(); | |
794 return GoogleServiceAuthError::FromConnectionError(status.error()); | |
795 } | |
796 } else { | |
797 if (IsSecondFactorSuccess(data)) { | |
798 return GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR); | |
799 } | |
800 | |
801 std::string error; | |
802 std::string url; | |
803 std::string captcha_url; | |
804 std::string captcha_token; | |
805 ParseClientLoginFailure(data, &error, &url, &captcha_url, &captcha_token); | |
806 DLOG(WARNING) << "ClientLogin failed with " << error; | |
807 | |
808 if (error == kCaptchaError) { | |
809 GURL image_url( | |
810 GaiaUrls::GetInstance()->captcha_url_prefix() + captcha_url); | |
811 GURL unlock_url(url); | |
812 return GoogleServiceAuthError::FromClientLoginCaptchaChallenge( | |
813 captcha_token, image_url, unlock_url); | |
814 } | |
815 if (error == kAccountDeletedError) | |
816 return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DELETED); | |
817 if (error == kAccountDisabledError) | |
818 return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED); | |
819 if (error == kBadAuthenticationError) { | |
820 return GoogleServiceAuthError( | |
821 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); | |
822 } | |
823 if (error == kServiceUnavailableError) { | |
824 return GoogleServiceAuthError( | |
825 GoogleServiceAuthError::SERVICE_UNAVAILABLE); | |
826 } | |
827 | |
828 DLOG(WARNING) << "Incomprehensible response from Google Accounts servers."; | |
829 return GoogleServiceAuthError( | |
830 GoogleServiceAuthError::SERVICE_UNAVAILABLE); | |
831 } | |
832 | |
833 NOTREACHED(); | |
834 return GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE); | |
835 } | |
836 | |
837 // static | |
838 GoogleServiceAuthError GaiaAuthFetcher::GenerateOAuthLoginError( | |
839 const std::string& data, | |
840 const net::URLRequestStatus& status) { | |
841 if (!status.is_success()) { | |
842 if (status.status() == net::URLRequestStatus::CANCELED) { | |
843 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED); | |
844 } else { | |
845 DLOG(WARNING) << "Could not reach Google Accounts servers: errno " | |
846 << status.error(); | |
847 return GoogleServiceAuthError::FromConnectionError(status.error()); | |
848 } | |
849 } else { | |
850 if (IsSecondFactorSuccess(data)) { | |
851 return GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR); | |
852 } | |
853 | |
854 std::string error; | |
855 std::string url; | |
856 std::string captcha_url; | |
857 std::string captcha_token; | |
858 ParseClientLoginFailure(data, &error, &url, &captcha_url, &captcha_token); | |
859 LOG(WARNING) << "OAuthLogin failed with " << error; | |
860 | |
861 if (error == kCaptchaErrorCode) { | |
862 GURL image_url( | |
863 GaiaUrls::GetInstance()->captcha_url_prefix() + captcha_url); | |
864 GURL unlock_url(url); | |
865 return GoogleServiceAuthError::FromClientLoginCaptchaChallenge( | |
866 captcha_token, image_url, unlock_url); | |
867 } | |
868 if (error == kAccountDeletedErrorCode) | |
869 return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DELETED); | |
870 if (error == kAccountDisabledErrorCode) | |
871 return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED); | |
872 if (error == kBadAuthenticationErrorCode) { | |
873 return GoogleServiceAuthError( | |
874 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); | |
875 } | |
876 if (error == kServiceUnavailableErrorCode) { | |
877 return GoogleServiceAuthError( | |
878 GoogleServiceAuthError::SERVICE_UNAVAILABLE); | |
879 } | |
880 | |
881 DLOG(WARNING) << "Incomprehensible response from Google Accounts servers."; | |
882 return GoogleServiceAuthError( | |
883 GoogleServiceAuthError::SERVICE_UNAVAILABLE); | |
884 } | |
885 | |
886 NOTREACHED(); | |
887 return GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE); | |
888 } | |
889 | |
890 void GaiaAuthFetcher::OnClientLoginFetched(const std::string& data, | |
891 const net::URLRequestStatus& status, | |
892 int response_code) { | |
893 if (status.is_success() && response_code == net::HTTP_OK) { | |
894 DVLOG(1) << "ClientLogin successful!"; | |
895 std::string sid; | |
896 std::string lsid; | |
897 std::string token; | |
898 ParseClientLoginResponse(data, &sid, &lsid, &token); | |
899 consumer_->OnClientLoginSuccess( | |
900 GaiaAuthConsumer::ClientLoginResult(sid, lsid, token, data)); | |
901 } else { | |
902 consumer_->OnClientLoginFailure(GenerateAuthError(data, status)); | |
903 } | |
904 } | |
905 | |
906 void GaiaAuthFetcher::OnIssueAuthTokenFetched( | |
907 const std::string& data, | |
908 const net::URLRequestStatus& status, | |
909 int response_code) { | |
910 if (status.is_success() && response_code == net::HTTP_OK) { | |
911 // Only the bare token is returned in the body of this Gaia call | |
912 // without any padding. | |
913 consumer_->OnIssueAuthTokenSuccess(requested_service_, data); | |
914 } else { | |
915 consumer_->OnIssueAuthTokenFailure(requested_service_, | |
916 GenerateAuthError(data, status)); | |
917 } | |
918 } | |
919 | |
920 void GaiaAuthFetcher::OnClientLoginToOAuth2Fetched( | |
921 const std::string& data, | |
922 const net::ResponseCookies& cookies, | |
923 const net::URLRequestStatus& status, | |
924 int response_code) { | |
925 if (status.is_success() && response_code == net::HTTP_OK) { | |
926 std::string auth_code; | |
927 ParseClientLoginToOAuth2Response(cookies, &auth_code); | |
928 StartOAuth2TokenPairFetch(auth_code); | |
929 } else { | |
930 consumer_->OnClientOAuthFailure(GenerateAuthError(data, status)); | |
931 } | |
932 } | |
933 | |
934 void GaiaAuthFetcher::StartOAuth2TokenPairFetch(const std::string& auth_code) { | |
935 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
936 | |
937 DVLOG(1) << "Starting OAuth token pair fetch"; | |
938 request_body_ = MakeGetTokenPairBody(auth_code); | |
939 fetcher_.reset(CreateGaiaFetcher(getter_, | |
940 request_body_, | |
941 "", | |
942 oauth2_token_gurl_, | |
943 kLoadFlagsIgnoreCookies, | |
944 this)); | |
945 fetch_pending_ = true; | |
946 fetcher_->Start(); | |
947 } | |
948 | |
949 void GaiaAuthFetcher::OnOAuth2TokenPairFetched( | |
950 const std::string& data, | |
951 const net::URLRequestStatus& status, | |
952 int response_code) { | |
953 std::string refresh_token; | |
954 std::string access_token; | |
955 int expires_in_secs = 0; | |
956 | |
957 bool success = false; | |
958 if (status.is_success() && response_code == net::HTTP_OK) { | |
959 scoped_ptr<base::Value> value(base::JSONReader::Read(data)); | |
960 if (value.get() && value->GetType() == base::Value::TYPE_DICTIONARY) { | |
961 DictionaryValue* dict = static_cast<DictionaryValue*>(value.get()); | |
962 success = ExtractOAuth2TokenPairResponse(dict, &refresh_token, | |
963 &access_token, &expires_in_secs); | |
964 } | |
965 } | |
966 | |
967 if (success) { | |
968 consumer_->OnClientOAuthSuccess( | |
969 GaiaAuthConsumer::ClientOAuthResult(refresh_token, access_token, | |
970 expires_in_secs)); | |
971 } else { | |
972 consumer_->OnClientOAuthFailure(GenerateAuthError(data, status)); | |
973 } | |
974 } | |
975 | |
976 void GaiaAuthFetcher::OnGetUserInfoFetched( | |
977 const std::string& data, | |
978 const net::URLRequestStatus& status, | |
979 int response_code) { | |
980 if (status.is_success() && response_code == net::HTTP_OK) { | |
981 std::vector<std::pair<std::string, std::string> > tokens; | |
982 UserInfoMap matches; | |
983 base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens); | |
984 std::vector<std::pair<std::string, std::string> >::iterator i; | |
985 for (i = tokens.begin(); i != tokens.end(); ++i) { | |
986 matches[i->first] = i->second; | |
987 } | |
988 consumer_->OnGetUserInfoSuccess(matches); | |
989 } else { | |
990 consumer_->OnGetUserInfoFailure(GenerateAuthError(data, status)); | |
991 } | |
992 } | |
993 | |
994 void GaiaAuthFetcher::OnMergeSessionFetched(const std::string& data, | |
995 const net::URLRequestStatus& status, | |
996 int response_code) { | |
997 if (status.is_success() && response_code == net::HTTP_OK) { | |
998 consumer_->OnMergeSessionSuccess(data); | |
999 } else { | |
1000 consumer_->OnMergeSessionFailure(GenerateAuthError(data, status)); | |
1001 } | |
1002 } | |
1003 | |
1004 void GaiaAuthFetcher::OnUberAuthTokenFetch(const std::string& data, | |
1005 const net::URLRequestStatus& status, | |
1006 int response_code) { | |
1007 if (status.is_success() && response_code == net::HTTP_OK) { | |
1008 consumer_->OnUberAuthTokenSuccess(data); | |
1009 } else { | |
1010 consumer_->OnUberAuthTokenFailure(GenerateAuthError(data, status)); | |
1011 } | |
1012 } | |
1013 | |
1014 void GaiaAuthFetcher::OnClientOAuthFetched(const std::string& data, | |
1015 const net::URLRequestStatus& status, | |
1016 int response_code) { | |
1017 std::string refresh_token; | |
1018 std::string access_token; | |
1019 int expires_in_secs = 0; | |
1020 | |
1021 bool success = false; | |
1022 if (status.is_success() && response_code == net::HTTP_OK) { | |
1023 scoped_ptr<base::Value> value(base::JSONReader::Read(data)); | |
1024 if (value.get() && value->GetType() == base::Value::TYPE_DICTIONARY) { | |
1025 DictionaryValue* dict = static_cast<DictionaryValue*>(value.get()); | |
1026 DictionaryValue* dict_oauth2; | |
1027 if (dict->GetDictionaryWithoutPathExpansion("oauth2", &dict_oauth2)) { | |
1028 success = ExtractOAuth2TokenPairResponse(dict_oauth2, &refresh_token, | |
1029 &access_token, | |
1030 &expires_in_secs); | |
1031 } | |
1032 } | |
1033 } | |
1034 | |
1035 // TODO(rogerta): for now this reuses the OnOAuthLoginTokenXXX callbacks | |
1036 // since the data is exactly the same. This ignores the optional | |
1037 // persistent_id data in the response, which we may need to handle. | |
1038 // If we do, we'll need to modify ExtractOAuth2TokenPairResponse() to parse | |
1039 // the optional data and declare new consumer callbacks to take it. | |
1040 if (success) { | |
1041 consumer_->OnClientOAuthSuccess( | |
1042 GaiaAuthConsumer::ClientOAuthResult(refresh_token, access_token, | |
1043 expires_in_secs)); | |
1044 } else { | |
1045 consumer_->OnClientOAuthFailure(GenerateClientOAuthError(data, status)); | |
1046 } | |
1047 } | |
1048 | |
1049 void GaiaAuthFetcher::OnOAuthLoginFetched(const std::string& data, | |
1050 const net::URLRequestStatus& status, | |
1051 int response_code) { | |
1052 if (status.is_success() && response_code == net::HTTP_OK) { | |
1053 DVLOG(1) << "ClientLogin successful!"; | |
1054 std::string sid; | |
1055 std::string lsid; | |
1056 std::string token; | |
1057 ParseClientLoginResponse(data, &sid, &lsid, &token); | |
1058 consumer_->OnClientLoginSuccess( | |
1059 GaiaAuthConsumer::ClientLoginResult(sid, lsid, token, data)); | |
1060 } else { | |
1061 consumer_->OnClientLoginFailure(GenerateAuthError(data, status)); | |
1062 } | |
1063 } | |
1064 | |
1065 void GaiaAuthFetcher::OnURLFetchComplete(const net::URLFetcher* source) { | |
1066 fetch_pending_ = false; | |
1067 // Some of the GAIA requests perform redirects, which results in the final | |
1068 // URL of the fetcher not being the original URL requested. Therefore use | |
1069 // the original URL when determining which OnXXX function to call. | |
1070 const GURL& url = source->GetOriginalURL(); | |
1071 const net::URLRequestStatus& status = source->GetStatus(); | |
1072 int response_code = source->GetResponseCode(); | |
1073 std::string data; | |
1074 source->GetResponseAsString(&data); | |
1075 DVLOG(2) << "Gaia fetcher response code: " << response_code; | |
1076 DVLOG(2) << "Gaia fetcher response data: " << data; | |
1077 if (url == client_login_gurl_) { | |
1078 OnClientLoginFetched(data, status, response_code); | |
1079 } else if (url == issue_auth_token_gurl_) { | |
1080 OnIssueAuthTokenFetched(data, status, response_code); | |
1081 } else if (url == client_login_to_oauth2_gurl_) { | |
1082 OnClientLoginToOAuth2Fetched( | |
1083 data, source->GetCookies(), status, response_code); | |
1084 } else if (url == oauth2_token_gurl_) { | |
1085 OnOAuth2TokenPairFetched(data, status, response_code); | |
1086 } else if (url == get_user_info_gurl_) { | |
1087 OnGetUserInfoFetched(data, status, response_code); | |
1088 } else if (url == merge_session_gurl_) { | |
1089 OnMergeSessionFetched(data, status, response_code); | |
1090 } else if (url == uberauth_token_gurl_) { | |
1091 OnUberAuthTokenFetch(data, status, response_code); | |
1092 } else if (url == client_oauth_gurl_) { | |
1093 OnClientOAuthFetched(data, status, response_code); | |
1094 } else if (url == oauth_login_gurl_) { | |
1095 OnOAuthLoginFetched(data, status, response_code); | |
1096 } else { | |
1097 NOTREACHED(); | |
1098 } | |
1099 } | |
1100 | |
1101 // static | |
1102 bool GaiaAuthFetcher::IsSecondFactorSuccess( | |
1103 const std::string& alleged_error) { | |
1104 return alleged_error.find(kSecondFactor) != | |
1105 std::string::npos; | |
1106 } | |
OLD | NEW |