gaia_auth_fetcher.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_auth_fetcher.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_writer.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stringprintf.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_auth_consumer.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/load_flags.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/http/http_response_headers.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_status_code.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_status.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kLoadFlagsIgnoreCookies = net::LOAD_DO_NOT_SEND_COOKIES |
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    net::LOAD_DO_NOT_SAVE_COOKIES;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool CookiePartsContains(const std::vector<std::string>& parts,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const char* part) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::find(parts.begin(), parts.end(), part) != parts.end();
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtractOAuth2TokenPairResponse(DictionaryValue* dict,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    std::string* refresh_token,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    std::string* access_token,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    int* expires_in_secs) {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(refresh_token);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(access_token);
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(expires_in_secs);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dict->GetStringWithoutPathExpansion("refresh_token", refresh_token) ||
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !dict->GetStringWithoutPathExpansion("access_token", access_token) ||
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !dict->GetIntegerWithoutPathExpansion("expires_in", expires_in_secs)) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(chron): Add sourceless version of this formatter.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kClientLoginFormat[] =
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Email=%s&"
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Passwd=%s&"
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "PersistentCookie=%s&"
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "accountType=%s&"
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "source=%s&"
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "service=%s";
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kClientLoginCaptchaFormat[] =
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Email=%s&"
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Passwd=%s&"
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "PersistentCookie=%s&"
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "accountType=%s&"
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "source=%s&"
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "service=%s&"
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "logintoken=%s&"
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "logincaptcha=%s";
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kIssueAuthTokenFormat[] =
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "SID=%s&"
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "LSID=%s&"
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "service=%s&"
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Session=%s";
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kClientLoginToOAuth2BodyFormat[] =
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "scope=%s&client_id=%s";
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kOAuth2CodeToTokenPairBodyFormat[] =
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "scope=%s&"
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "grant_type=authorization_code&"
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "client_id=%s&"
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "client_secret=%s&"
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "code=%s";
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kGetUserInfoFormat[] =
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "LSID=%s";
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kMergeSessionFormat[] =
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "uberauth=%s&"
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "continue=%s&"
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "source=%s";
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kUberAuthTokenURLFormat[] =
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "%s?source=%s&"
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "issueuberauth=1";
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kOAuthLoginFormat[] = "service=%s&source=%s";
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kAccountDeletedError[] = "AccountDeleted";
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kAccountDeletedErrorCode[] = "adel";
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kAccountDisabledError[] = "AccountDisabled";
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kAccountDisabledErrorCode[] = "adis";
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kBadAuthenticationError[] = "BadAuthentication";
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kBadAuthenticationErrorCode[] = "badauth";
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kCaptchaError[] = "CaptchaRequired";
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kCaptchaErrorCode[] = "cr";
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kServiceUnavailableError[] =
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "ServiceUnavailable";
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kServiceUnavailableErrorCode[] =
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "ire";
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kErrorParam[] = "Error";
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kErrorUrlParam[] = "Url";
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kCaptchaUrlParam[] = "CaptchaUrl";
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kCaptchaTokenParam[] = "CaptchaToken";
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kNeedsAdditional[] = "NeedsAdditional";
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kCaptcha[] = "Captcha";
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kTwoFactor[] = "TwoStep";
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kCookiePersistence[] = "true";
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(johnnyg): When hosted accounts are supported by sync,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we can always use "HOSTED_OR_GOOGLE"
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kAccountTypeHostedOrGoogle[] =
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "HOSTED_OR_GOOGLE";
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kAccountTypeGoogle[] =
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "GOOGLE";
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kSecondFactor[] = "Info=InvalidSecondFactor";
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kAuthHeaderFormat[] =
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Authorization: GoogleLogin auth=%s";
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kOAuthHeaderFormat[] = "Authorization: OAuth %s";
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char GaiaAuthFetcher::kOAuth2BearerHeaderFormat[] =
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "Authorization: Bearer %s";
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kClientLoginToOAuth2CookiePartSecure[] = "Secure";
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kClientLoginToOAuth2CookiePartHttpOnly[] =
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "HttpOnly";
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char GaiaAuthFetcher::kClientLoginToOAuth2CookiePartCodePrefix[] =
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "oauth_code=";
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int GaiaAuthFetcher::kClientLoginToOAuth2CookiePartCodePrefixLength =
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    arraysize(GaiaAuthFetcher::kClientLoginToOAuth2CookiePartCodePrefix) - 1;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GaiaAuthFetcher::GaiaAuthFetcher(GaiaAuthConsumer* consumer,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 const std::string& source,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 net::URLRequestContextGetter* getter)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : consumer_(consumer),
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      getter_(getter),
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      source_(source),
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_login_gurl_(GaiaUrls::GetInstance()->client_login_url()),
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      issue_auth_token_gurl_(GaiaUrls::GetInstance()->issue_auth_token_url()),
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      oauth2_token_gurl_(GaiaUrls::GetInstance()->oauth2_token_url()),
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      get_user_info_gurl_(GaiaUrls::GetInstance()->get_user_info_url()),
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      merge_session_gurl_(GaiaUrls::GetInstance()->merge_session_url()),
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uberauth_token_gurl_(base::StringPrintf(kUberAuthTokenURLFormat,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GaiaUrls::GetInstance()->oauth1_login_url().c_str(), source.c_str())),
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_oauth_gurl_(GaiaUrls::GetInstance()->client_oauth_url()),
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      oauth_login_gurl_(GaiaUrls::GetInstance()->oauth1_login_url()),
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_login_to_oauth2_gurl_(
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GaiaUrls::GetInstance()->client_login_to_oauth2_url()),
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fetch_pending_(false) {}
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GaiaAuthFetcher::~GaiaAuthFetcher() {}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GaiaAuthFetcher::HasPendingFetch() {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return fetch_pending_;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::CancelRequest() {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_.reset();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetch_pending_ = false;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)net::URLFetcher* GaiaAuthFetcher::CreateGaiaFetcher(
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLRequestContextGetter* getter,
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& body,
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& headers,
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& gaia_gurl,
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int load_flags,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::URLFetcherDelegate* delegate) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::URLFetcher* to_return = net::URLFetcher::Create(
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      0, gaia_gurl,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      body == "" ? net::URLFetcher::GET : net::URLFetcher::POST,
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  to_return->SetRequestContext(getter);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  to_return->SetUploadData("application/x-www-form-urlencoded", body);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(2) << "Gaia fetcher URL: " << gaia_gurl.spec();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(2) << "Gaia fetcher headers: " << headers;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(2) << "Gaia fetcher body: " << body;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The Gaia token exchange requests do not require any cookie-based
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // identification as part of requests.  We suppress sending any cookies to
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // maintain a separation between the user's browsing and Chrome's internal
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // services.  Where such mixing is desired (MergeSession), it will be done
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // explicitly.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  to_return->SetLoadFlags(load_flags);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Fetchers are sometimes cancelled because a network change was detected,
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // especially at startup and after sign-in on ChromeOS. Retrying once should
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // be enough in those cases; let the fetcher retry up to 3 times just in case.
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // http://crbug.com/163710
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  to_return->SetAutomaticallyRetryOnNetworkChanges(3);
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!headers.empty())
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to_return->SetExtraRequestHeaders(headers);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return to_return;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GaiaAuthFetcher::MakeClientLoginBody(
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& username,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& password,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& source,
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* service,
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& login_token,
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& login_captcha,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HostedAccountsSetting allow_hosted_accounts) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_username = net::EscapeUrlEncodedData(username, true);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_password = net::EscapeUrlEncodedData(password, true);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_login_token = net::EscapeUrlEncodedData(login_token,
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                              true);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_login_captcha = net::EscapeUrlEncodedData(login_captcha,
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                true);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* account_type = allow_hosted_accounts == HostedAccountsAllowed ?
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kAccountTypeHostedOrGoogle :
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kAccountTypeGoogle;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (login_token.empty() || login_captcha.empty()) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return base::StringPrintf(kClientLoginFormat,
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              encoded_username.c_str(),
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              encoded_password.c_str(),
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              kCookiePersistence,
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              account_type,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              source.c_str(),
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              service);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::StringPrintf(kClientLoginCaptchaFormat,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            encoded_username.c_str(),
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            encoded_password.c_str(),
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kCookiePersistence,
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            account_type,
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            source.c_str(),
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            service,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            encoded_login_token.c_str(),
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            encoded_login_captcha.c_str());
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GaiaAuthFetcher::MakeIssueAuthTokenBody(
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& sid,
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& lsid,
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* const service) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_sid = net::EscapeUrlEncodedData(sid, true);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_lsid = net::EscapeUrlEncodedData(lsid, true);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // All tokens should be session tokens except the gaia auth token.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool session = true;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!strcmp(service, GaiaConstants::kGaiaService))
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    session = false;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::StringPrintf(kIssueAuthTokenFormat,
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            encoded_sid.c_str(),
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            encoded_lsid.c_str(),
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            service,
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            session ? "true" : "false");
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GaiaAuthFetcher::MakeGetAuthCodeBody() {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_scope = net::EscapeUrlEncodedData(
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth1_login_scope(), true);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_client_id = net::EscapeUrlEncodedData(
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true);
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::StringPrintf(kClientLoginToOAuth2BodyFormat,
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            encoded_scope.c_str(),
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            encoded_client_id.c_str());
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GaiaAuthFetcher::MakeGetTokenPairBody(
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& auth_code) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_scope = net::EscapeUrlEncodedData(
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth1_login_scope(), true);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_client_id = net::EscapeUrlEncodedData(
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_client_secret = net::EscapeUrlEncodedData(
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), true);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_auth_code = net::EscapeUrlEncodedData(auth_code, true);
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::StringPrintf(kOAuth2CodeToTokenPairBodyFormat,
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            encoded_scope.c_str(),
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            encoded_client_id.c_str(),
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            encoded_client_secret.c_str(),
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            encoded_auth_code.c_str());
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GaiaAuthFetcher::MakeGetUserInfoBody(const std::string& lsid) {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_lsid = net::EscapeUrlEncodedData(lsid, true);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::StringPrintf(kGetUserInfoFormat, encoded_lsid.c_str());
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GaiaAuthFetcher::MakeMergeSessionBody(
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& auth_token,
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& continue_url,
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& source) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_auth_token = net::EscapeUrlEncodedData(auth_token, true);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_continue_url = net::EscapeUrlEncodedData(continue_url,
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                               true);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_source = net::EscapeUrlEncodedData(source, true);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::StringPrintf(kMergeSessionFormat,
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            encoded_auth_token.c_str(),
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            encoded_continue_url.c_str(),
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            encoded_source.c_str());
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GaiaAuthFetcher::MakeGetAuthCodeHeader(
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& auth_token) {
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::StringPrintf(kAuthHeaderFormat, auth_token.c_str());
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper method that extracts tokens from a successful reply.
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::ParseClientLoginResponse(const std::string& data,
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               std::string* sid,
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               std::string* lsid,
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               std::string* token) {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  using std::vector;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  using std::pair;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  using std::string;
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sid->clear();
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  lsid->clear();
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  token->clear();
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  vector<pair<string, string> > tokens;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (vector<pair<string, string> >::iterator i = tokens.begin();
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i != tokens.end(); ++i) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i->first == "SID") {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sid->assign(i->second);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (i->first == "LSID") {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      lsid->assign(i->second);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (i->first == "Auth") {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token->assign(i->second);
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If this was a request for uberauth token, then that's all we've got in
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // data.
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (sid->empty() && lsid->empty() && token->empty())
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    token->assign(data);
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GaiaAuthFetcher::MakeClientOAuthBody(
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& username,
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& password,
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<std::string>& scopes,
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& persistent_id,
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& friendly_name,
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& locale) {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString(GaiaConstants::kClientOAuthEmailKey, username);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString(GaiaConstants::kClientOAuthPasswordKey, password);
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::ListValue> scope_list(new base::ListValue);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < scopes.size(); ++i)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scope_list->Append(base::Value::CreateStringValue(scopes[i]));
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->Set(GaiaConstants::kClientOAuthScopesKey, scope_list.release());
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString(GaiaConstants::kClientOAuthOAuth2ClientIdKey,
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  GaiaUrls::GetInstance()->oauth2_chrome_client_id());
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // crbug.com/129600: use a less generic friendly name.
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString(GaiaConstants::kClientOAuthFriendlyDeviceNameKey,
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  friendly_name);
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::ListValue> accepts_challenge_list(new base::ListValue);
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  accepts_challenge_list->Append(base::Value::CreateStringValue(kCaptcha));
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  accepts_challenge_list->Append(base::Value::CreateStringValue(kTwoFactor));
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->Set(GaiaConstants::kClientOAuthAcceptsChallengesKey,
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            accepts_challenge_list.release());
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString(GaiaConstants::kClientOAuthLocaleKey, locale);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Chrome presently does not not support a web-fallback for ClientOAuth,
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // but need to hardcode an arbitrary one here since the endpoint expects it.
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString(GaiaConstants::kClientOAuthFallbackNameKey, "GetOAuth2Token");
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string json_string;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::JSONWriter::Write(dict.get(), &json_string);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return json_string;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GaiaAuthFetcher::MakeClientOAuthChallengeResponseBody(
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& name,
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& token,
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& solution) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string field_name = name == kTwoFactor ? "otp" : "solution";
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> challenge_reply(new base::DictionaryValue);
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  challenge_reply->SetString(GaiaConstants::kClientOAuthNameKey, name);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  challenge_reply->SetString(GaiaConstants::kClientOAuthChallengeTokenKey,
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             token);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  challenge_reply->SetString(field_name, solution);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->Set(GaiaConstants::kClientOAuthchallengeReplyKey,
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            challenge_reply.release());
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string json_string;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::JSONWriter::Write(dict.get(), &json_string);
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return json_string;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GaiaAuthFetcher::MakeOAuthLoginBody(const std::string& service,
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                const std::string& source) {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_service = net::EscapeUrlEncodedData(service, true);
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string encoded_source = net::EscapeUrlEncodedData(source, true);
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::StringPrintf(kOAuthLoginFormat,
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            encoded_service.c_str(),
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            encoded_source.c_str());
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::ParseClientLoginFailure(const std::string& data,
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              std::string* error,
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              std::string* error_url,
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              std::string* captcha_url,
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              std::string* captcha_token) {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  using std::vector;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  using std::pair;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  using std::string;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  vector<pair<string, string> > tokens;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens);
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (vector<pair<string, string> >::iterator i = tokens.begin();
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != tokens.end(); ++i) {
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i->first == kErrorParam) {
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error->assign(i->second);
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (i->first == kErrorUrlParam) {
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_url->assign(i->second);
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (i->first == kCaptchaUrlParam) {
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      captcha_url->assign(i->second);
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (i->first == kCaptchaTokenParam) {
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      captcha_token->assign(i->second);
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GaiaAuthFetcher::ParseClientLoginToOAuth2Response(
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::ResponseCookies& cookies,
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string* auth_code) {
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(auth_code);
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::ResponseCookies::const_iterator iter;
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = cookies.begin(); iter != cookies.end(); ++iter) {
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ParseClientLoginToOAuth2Cookie(*iter, auth_code))
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GaiaAuthFetcher::ParseClientLoginToOAuth2Cookie(const std::string& cookie,
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     std::string* auth_code) {
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> parts;
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SplitString(cookie, ';', &parts);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Per documentation, the cookie should have Secure and HttpOnly.
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CookiePartsContains(parts, kClientLoginToOAuth2CookiePartSecure) ||
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !CookiePartsContains(parts, kClientLoginToOAuth2CookiePartHttpOnly)) {
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string>::const_iterator iter;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = parts.begin(); iter != parts.end(); ++iter) {
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& part = *iter;
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (StartsWithASCII(
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        part, kClientLoginToOAuth2CookiePartCodePrefix, false)) {
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auth_code->assign(part.substr(
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kClientLoginToOAuth2CookiePartCodePrefixLength));
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GoogleServiceAuthError
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GaiaAuthFetcher::GenerateClientOAuthError(const std::string& data,
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          const net::URLRequestStatus& status) {
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::Value> value(base::JSONReader::Read(data));
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GenerateAuthError(data, status);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryValue* dict = static_cast<DictionaryValue*>(value.get());
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string cause;
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dict->GetStringWithoutPathExpansion("cause", &cause))
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GoogleServiceAuthError::FromClientOAuthError(data);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cause != kNeedsAdditional)
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GoogleServiceAuthError::FromClientOAuthError(data);
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryValue* challenge;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dict->GetDictionaryWithoutPathExpansion("challenge", &challenge))
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GoogleServiceAuthError::FromClientOAuthError(data);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string name;
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!challenge->GetStringWithoutPathExpansion("name", &name))
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GoogleServiceAuthError::FromClientOAuthError(data);
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (name == kCaptcha) {
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string token;
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string audio_url;
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string image_url;
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int image_width;
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int image_height;
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!challenge->GetStringWithoutPathExpansion("challenge_token", &token) ||
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !challenge->GetStringWithoutPathExpansion("audio_url", &audio_url) ||
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !challenge->GetStringWithoutPathExpansion("image_url", &image_url) ||
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !challenge->GetIntegerWithoutPathExpansion("image_width",
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   &image_width) ||
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !challenge->GetIntegerWithoutPathExpansion("image_height",
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   &image_height)) {
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError::FromClientOAuthError(data);
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GoogleServiceAuthError::FromCaptchaChallenge(token, GURL(audio_url),
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        GURL(image_url),
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        image_width,
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        image_height);
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (name == kTwoFactor) {
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string token;
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string prompt_text;
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string alternate_text;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int field_length;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The protocol doc says these are required, but in practice they are not
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // returned.  So only a missing challenge token will cause an error here.
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    challenge->GetStringWithoutPathExpansion("prompt_text", &prompt_text);
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    challenge->GetStringWithoutPathExpansion("alternate_text", &alternate_text);
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    challenge->GetIntegerWithoutPathExpansion("field_length", &field_length);
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!challenge->GetStringWithoutPathExpansion("challenge_token", &token))
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError::FromClientOAuthError(data);
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GoogleServiceAuthError::FromSecondFactorChallenge(token, prompt_text,
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                             alternate_text,
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                             field_length);
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GoogleServiceAuthError::FromClientOAuthError(data);
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::StartClientLogin(
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& username,
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& password,
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* const service,
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& login_token,
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& login_captcha,
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HostedAccountsSetting allow_hosted_accounts) {
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This class is thread agnostic, so be sure to call this only on the
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // same thread each time.
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Starting new ClientLogin fetch for:" << username;
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Must outlive fetcher_.
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_body_ = MakeClientLoginBody(username,
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      password,
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      source_,
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      service,
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      login_token,
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      login_captcha,
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      allow_hosted_accounts);
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_.reset(CreateGaiaFetcher(getter_,
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   request_body_,
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   "",
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   client_login_gurl_,
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   kLoadFlagsIgnoreCookies,
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   this));
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetch_pending_ = true;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::StartIssueAuthToken(const std::string& sid,
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          const std::string& lsid,
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          const char* const service) {
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Starting IssueAuthToken for: " << service;
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  requested_service_ = service;
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_body_ = MakeIssueAuthTokenBody(sid, lsid, service);
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_.reset(CreateGaiaFetcher(getter_,
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   request_body_,
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   "",
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   issue_auth_token_gurl_,
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   kLoadFlagsIgnoreCookies,
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   this));
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetch_pending_ = true;
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::StartLsoForOAuthLoginTokenExchange(
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& auth_token) {
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Starting OAuth login token exchange with auth_token";
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_body_ = MakeGetAuthCodeBody();
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  client_login_to_oauth2_gurl_ =
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GURL(GaiaUrls::GetInstance()->client_login_to_oauth2_url());
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_.reset(CreateGaiaFetcher(getter_,
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   request_body_,
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   MakeGetAuthCodeHeader(auth_token),
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   client_login_to_oauth2_gurl_,
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   kLoadFlagsIgnoreCookies,
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   this));
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetch_pending_ = true;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::StartCookieForOAuthLoginTokenExchange(
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& session_index) {
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Starting OAuth login token fetch with cookie jar";
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_body_ = MakeGetAuthCodeBody();
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string url = GaiaUrls::GetInstance()->client_login_to_oauth2_url();
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!session_index.empty())
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url += "?authuser=" + session_index;
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  client_login_to_oauth2_gurl_ = GURL(url);
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_.reset(CreateGaiaFetcher(getter_,
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   request_body_,
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   "",
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   client_login_to_oauth2_gurl_,
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   net::LOAD_NORMAL,
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   this));
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetch_pending_ = true;
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GaiaAuthFetcher::StartAuthCodeForOAuth2TokenExchange(
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& auth_code) {
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "Starting OAuth token pair fetch";
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request_body_ = MakeGetTokenPairBody(auth_code);
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fetcher_.reset(CreateGaiaFetcher(getter_,
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   request_body_,
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   "",
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   oauth2_token_gurl_,
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   kLoadFlagsIgnoreCookies,
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   this));
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fetch_pending_ = true;
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fetcher_->Start();
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::StartGetUserInfo(const std::string& lsid) {
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Starting GetUserInfo for lsid=" << lsid;
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_body_ = MakeGetUserInfoBody(lsid);
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_.reset(CreateGaiaFetcher(getter_,
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   request_body_,
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   "",
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   get_user_info_gurl_,
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   kLoadFlagsIgnoreCookies,
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   this));
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetch_pending_ = true;
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::StartMergeSession(const std::string& uber_token) {
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Starting MergeSession with uber_token=" << uber_token;
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The continue URL is a required parameter of the MergeSession API, but in
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this case we don't actually need or want to navigate to it.  Setting it to
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // an arbitrary Google URL.
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In order for the new session to be merged correctly, the server needs to
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // know what sessions already exist in the browser.  The fetcher needs to be
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // created such that it sends the cookies with the request, which is
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // different from all other requests the fetcher can make.
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string continue_url("http://www.google.com");
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_body_ = MakeMergeSessionBody(uber_token, continue_url, source_);
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_.reset(CreateGaiaFetcher(getter_,
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   request_body_,
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   "",
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   merge_session_gurl_,
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   net::LOAD_NORMAL,
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   this));
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetch_pending_ = true;
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::StartTokenFetchForUberAuthExchange(
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& access_token) {
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Starting StartTokenFetchForUberAuthExchange with access_token="
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           << access_token;
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string authentication_header =
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::StringPrintf(kOAuthHeaderFormat, access_token.c_str());
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_.reset(CreateGaiaFetcher(getter_,
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   "",
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   authentication_header,
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   uberauth_token_gurl_,
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   kLoadFlagsIgnoreCookies,
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   this));
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetch_pending_ = true;
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::StartClientOAuth(const std::string& username,
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const std::string& password,
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const std::vector<std::string>& scopes,
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const std::string& persistent_id,
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const std::string& locale) {
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_body_ = MakeClientOAuthBody(username, password, scopes, persistent_id,
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      source_, locale);
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_.reset(CreateGaiaFetcher(getter_,
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   request_body_,
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   "",
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   client_oauth_gurl_,
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   kLoadFlagsIgnoreCookies,
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   this));
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetch_pending_ = true;
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::StartClientOAuthChallengeResponse(
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GoogleServiceAuthError::State type,
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& token,
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& solution) {
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string name;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GoogleServiceAuthError::CAPTCHA_REQUIRED:
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name = kCaptcha;
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GoogleServiceAuthError::TWO_FACTOR:
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name = kTwoFactor;
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_body_ = MakeClientOAuthChallengeResponseBody(name, token, solution);
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_.reset(CreateGaiaFetcher(getter_,
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   request_body_,
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   "",
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   client_oauth_gurl_,
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   kLoadFlagsIgnoreCookies,
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   this));
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetch_pending_ = true;
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::StartOAuthLogin(const std::string& access_token,
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const std::string& service) {
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_body_ = MakeOAuthLoginBody(service, source_);
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string authentication_header =
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::StringPrintf(kOAuth2BearerHeaderFormat, access_token.c_str());
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_.reset(CreateGaiaFetcher(getter_,
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   request_body_,
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   authentication_header,
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   oauth_login_gurl_,
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   kLoadFlagsIgnoreCookies,
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   this));
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetch_pending_ = true;
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GoogleServiceAuthError GaiaAuthFetcher::GenerateAuthError(
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& data,
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLRequestStatus& status) {
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!status.is_success()) {
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status.status() == net::URLRequestStatus::CANCELED) {
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(WARNING) << "Could not reach Google Accounts servers: errno "
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << status.error();
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError::FromConnectionError(status.error());
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsSecondFactorSuccess(data)) {
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR);
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string error;
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string url;
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string captcha_url;
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string captcha_token;
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ParseClientLoginFailure(data, &error, &url, &captcha_url, &captcha_token);
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "ClientLogin failed with " << error;
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error == kCaptchaError) {
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GURL image_url(
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GaiaUrls::GetInstance()->captcha_url_prefix() + captcha_url);
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GURL unlock_url(url);
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError::FromClientLoginCaptchaChallenge(
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          captcha_token, image_url, unlock_url);
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error == kAccountDeletedError)
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DELETED);
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error == kAccountDisabledError)
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED);
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error == kBadAuthenticationError) {
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError(
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error == kServiceUnavailableError) {
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError(
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GoogleServiceAuthError::SERVICE_UNAVAILABLE);
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Incomprehensible response from Google Accounts servers.";
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GoogleServiceAuthError(
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GoogleServiceAuthError::SERVICE_UNAVAILABLE);
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE);
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GoogleServiceAuthError GaiaAuthFetcher::GenerateOAuthLoginError(
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& data,
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLRequestStatus& status) {
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!status.is_success()) {
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (status.status() == net::URLRequestStatus::CANCELED) {
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(WARNING) << "Could not reach Google Accounts servers: errno "
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << status.error();
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError::FromConnectionError(status.error());
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsSecondFactorSuccess(data)) {
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR);
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string error;
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string url;
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string captcha_url;
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string captcha_token;
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ParseClientLoginFailure(data, &error, &url, &captcha_url, &captcha_token);
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "OAuthLogin failed with " << error;
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error == kCaptchaErrorCode) {
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GURL image_url(
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GaiaUrls::GetInstance()->captcha_url_prefix() + captcha_url);
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GURL unlock_url(url);
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError::FromClientLoginCaptchaChallenge(
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          captcha_token, image_url, unlock_url);
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error == kAccountDeletedErrorCode)
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DELETED);
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error == kAccountDisabledErrorCode)
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED);
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error == kBadAuthenticationErrorCode) {
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError(
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error == kServiceUnavailableErrorCode) {
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GoogleServiceAuthError(
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GoogleServiceAuthError::SERVICE_UNAVAILABLE);
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Incomprehensible response from Google Accounts servers.";
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GoogleServiceAuthError(
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GoogleServiceAuthError::SERVICE_UNAVAILABLE);
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE);
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::OnClientLoginFetched(const std::string& data,
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const net::URLRequestStatus& status,
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int response_code) {
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.is_success() && response_code == net::HTTP_OK) {
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "ClientLogin successful!";
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string sid;
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string lsid;
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string token;
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ParseClientLoginResponse(data, &sid, &lsid, &token);
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnClientLoginSuccess(
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GaiaAuthConsumer::ClientLoginResult(sid, lsid, token, data));
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnClientLoginFailure(GenerateAuthError(data, status));
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::OnIssueAuthTokenFetched(
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& data,
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLRequestStatus& status,
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int response_code) {
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.is_success() && response_code == net::HTTP_OK) {
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only the bare token is returned in the body of this Gaia call
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // without any padding.
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnIssueAuthTokenSuccess(requested_service_, data);
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnIssueAuthTokenFailure(requested_service_,
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GenerateAuthError(data, status));
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::OnClientLoginToOAuth2Fetched(
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& data,
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::ResponseCookies& cookies,
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLRequestStatus& status,
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int response_code) {
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.is_success() && response_code == net::HTTP_OK) {
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string auth_code;
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ParseClientLoginToOAuth2Response(cookies, &auth_code);
9612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartAuthCodeForOAuth2TokenExchange(auth_code);
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnClientOAuthFailure(GenerateAuthError(data, status));
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::OnOAuth2TokenPairFetched(
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& data,
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLRequestStatus& status,
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int response_code) {
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string refresh_token;
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string access_token;
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int expires_in_secs = 0;
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.is_success() && response_code == net::HTTP_OK) {
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<base::Value> value(base::JSONReader::Read(data));
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (value.get() && value->GetType() == base::Value::TYPE_DICTIONARY) {
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DictionaryValue* dict = static_cast<DictionaryValue*>(value.get());
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      success = ExtractOAuth2TokenPairResponse(dict, &refresh_token,
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               &access_token, &expires_in_secs);
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (success) {
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnClientOAuthSuccess(
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GaiaAuthConsumer::ClientOAuthResult(refresh_token, access_token,
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            expires_in_secs));
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnClientOAuthFailure(GenerateAuthError(data, status));
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::OnGetUserInfoFetched(
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& data,
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLRequestStatus& status,
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int response_code) {
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.is_success() && response_code == net::HTTP_OK) {
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::pair<std::string, std::string> > tokens;
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UserInfoMap matches;
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens);
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::pair<std::string, std::string> >::iterator i;
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (i = tokens.begin(); i != tokens.end(); ++i) {
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      matches[i->first] = i->second;
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnGetUserInfoSuccess(matches);
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnGetUserInfoFailure(GenerateAuthError(data, status));
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::OnMergeSessionFetched(const std::string& data,
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const net::URLRequestStatus& status,
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            int response_code) {
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.is_success() && response_code == net::HTTP_OK) {
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnMergeSessionSuccess(data);
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnMergeSessionFailure(GenerateAuthError(data, status));
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::OnUberAuthTokenFetch(const std::string& data,
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const net::URLRequestStatus& status,
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int response_code) {
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.is_success() && response_code == net::HTTP_OK) {
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnUberAuthTokenSuccess(data);
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnUberAuthTokenFailure(GenerateAuthError(data, status));
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::OnClientOAuthFetched(const std::string& data,
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           const net::URLRequestStatus& status,
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           int response_code) {
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string refresh_token;
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string access_token;
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int expires_in_secs = 0;
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.is_success() && response_code == net::HTTP_OK) {
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<base::Value> value(base::JSONReader::Read(data));
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (value.get() && value->GetType() == base::Value::TYPE_DICTIONARY) {
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DictionaryValue* dict = static_cast<DictionaryValue*>(value.get());
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DictionaryValue* dict_oauth2;
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (dict->GetDictionaryWithoutPathExpansion("oauth2", &dict_oauth2)) {
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        success = ExtractOAuth2TokenPairResponse(dict_oauth2, &refresh_token,
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &access_token,
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 &expires_in_secs);
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(rogerta): for now this reuses the OnOAuthLoginTokenXXX callbacks
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // since the data is exactly the same.  This ignores the optional
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // persistent_id data in the response, which we may need to handle.
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we do, we'll need to modify ExtractOAuth2TokenPairResponse() to parse
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the optional data and declare new consumer callbacks to take it.
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (success) {
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnClientOAuthSuccess(
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GaiaAuthConsumer::ClientOAuthResult(refresh_token, access_token,
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            expires_in_secs));
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnClientOAuthFailure(GenerateClientOAuthError(data, status));
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::OnOAuthLoginFetched(const std::string& data,
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          const net::URLRequestStatus& status,
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          int response_code) {
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status.is_success() && response_code == net::HTTP_OK) {
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "ClientLogin successful!";
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string sid;
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string lsid;
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string token;
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ParseClientLoginResponse(data, &sid, &lsid, &token);
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnClientLoginSuccess(
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GaiaAuthConsumer::ClientLoginResult(sid, lsid, token, data));
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    consumer_->OnClientLoginFailure(GenerateAuthError(data, status));
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaAuthFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetch_pending_ = false;
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some of the GAIA requests perform redirects, which results in the final
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // URL of the fetcher not being the original URL requested.  Therefore use
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the original URL when determining which OnXXX function to call.
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const GURL& url = source->GetOriginalURL();
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const net::URLRequestStatus& status = source->GetStatus();
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int response_code = source->GetResponseCode();
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string data;
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  source->GetResponseAsString(&data);
10932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifndef NDEBUG
10942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string headers;
10952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (source->GetResponseHeaders())
10962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    source->GetResponseHeaders()->GetNormalizedHeaders(&headers);
10972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(2) << "Response " << url.spec() << ", code = " << response_code << "\n"
10982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << headers << "\n";
10992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(2) << "data: " << data << "\n";
11002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
11012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Retrieve the response headers from the request.  Must only be called after
11022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the OnURLFetchComplete callback has run.
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url == client_login_gurl_) {
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnClientLoginFetched(data, status, response_code);
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (url == issue_auth_token_gurl_) {
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnIssueAuthTokenFetched(data, status, response_code);
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (url == client_login_to_oauth2_gurl_) {
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnClientLoginToOAuth2Fetched(
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        data, source->GetCookies(), status, response_code);
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (url == oauth2_token_gurl_) {
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnOAuth2TokenPairFetched(data, status, response_code);
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (url == get_user_info_gurl_) {
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnGetUserInfoFetched(data, status, response_code);
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (url == merge_session_gurl_) {
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnMergeSessionFetched(data, status, response_code);
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (url == uberauth_token_gurl_) {
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnUberAuthTokenFetch(data, status, response_code);
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (url == client_oauth_gurl_) {
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnClientOAuthFetched(data, status, response_code);
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (url == oauth_login_gurl_) {
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnOAuthLoginFetched(data, status, response_code);
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GaiaAuthFetcher::IsSecondFactorSuccess(
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& alleged_error) {
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return alleged_error.find(kSecondFactor) !=
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string::npos;
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1133