gaia_auth_fetcher.h revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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)#ifndef GOOGLE_APIS_GAIA_GAIA_AUTH_FETCHER_H_ 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define GOOGLE_APIS_GAIA_GAIA_AUTH_FETCHER_H_ 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/gtest_prod_util.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_auth_consumer.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "googleurl/src/gurl.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher_delegate.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Authenticate a user against the Google Accounts ClientLogin API 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with various capabilities and return results to a GaiaAuthConsumer. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In the future, we will also issue auth tokens from this class. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class should be used on a single thread, but it can be whichever thread 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that you like. 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class can handle one request at a time on any thread. To parallelize 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// requests, create multiple GaiaAuthFetcher's. 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GaiaAuthFetcherTest; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class URLFetcher; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class URLRequestContextGetter; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class URLRequestStatus; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GaiaAuthFetcher : public net::URLFetcherDelegate { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum HostedAccountsSetting { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HostedAccountsAllowed, 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HostedAccountsNotAllowed 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Magic string indicating that, while a second factor is still 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // needed to complete authentication, the user provided the right password. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kSecondFactor[]; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will later be hidden behind an auth service which caches 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tokens. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GaiaAuthFetcher(GaiaAuthConsumer* consumer, 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& source, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequestContextGetter* getter); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~GaiaAuthFetcher(); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a request to obtain the SID and LSID cookies for the the account 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // identified by |username| and |password|. If |service| is not null or 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // empty, then also obtains a service token for specified service. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If this is a second call because of captcha challenge, then the 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |login_token| and |login_captcha| arugment should correspond to the 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // solution of the challenge. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either OnClientLoginSuccess or OnClientLoginFailure will be 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // called on the consumer on the original thread. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartClientLogin(const std::string& username, 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& password, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* const service, 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& login_token, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& login_captcha, 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HostedAccountsSetting allow_hosted_accounts); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a request to obtain service token for the the account identified by 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |sid| and |lsid| and the |service|. 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either OnIssueAuthTokenSuccess or OnIssueAuthTokenFailure will be 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // called on the consumer on the original thread. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartIssueAuthToken(const std::string& sid, 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& lsid, 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* const service); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Start a request to obtain |service| token for the the account identified by 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |uber_token|. 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Either OnIssueAuthTokenSuccess or OnIssueAuthTokenFailure will be 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // called on the consumer on the original thread. 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void StartTokenAuth(const std::string& uber_token, 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const char* const service); 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Start a request to obtain service token for the the account identified by 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |oauth2_access_token| and the |service|. 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Either OnIssueAuthTokenSuccess or OnIssueAuthTokenFailure will be 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // called on the consumer on the original thread. 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void StartIssueAuthTokenForOAuth2(const std::string& oauth2_access_token, 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const char* const service); 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a request to exchange an "lso" service token given by |auth_token| 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for an OAuthLogin-scoped oauth2 token. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either OnClientOAuthSuccess or OnClientOAuthFailure will be 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // called on the consumer on the original thread. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartLsoForOAuthLoginTokenExchange(const std::string& auth_token); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Start a request to revoke |auth_token|. 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Either OnRevokeOAuth2TokenSuccess or OnRevokeOAuth2TokenSuccess will be 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // called on the consumer on the original thread. 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void StartRevokeOAuth2Token(const std::string& auth_token); 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a request to exchange the cookies of a signed-in user session 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for an OAuthLogin-scoped oauth2 token. In the case of a session with 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // multiple accounts signed in, |session_index| indicate the which of accounts 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // within the session. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either OnClientOAuthSuccess or OnClientOAuthFailure will be 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // called on the consumer on the original thread. 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartCookieForOAuthLoginTokenExchange(const std::string& session_index); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Start a request to exchange the authorization code for an OAuthLogin-scoped 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // oauth2 token. 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Either OnClientOAuthSuccess or OnClientOAuthFailure will be 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // called on the consumer on the original thread. 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void StartAuthCodeForOAuth2TokenExchange(const std::string& auth_code); 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a request to get user info for the account identified by |lsid|. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either OnGetUserInfoSuccess or OnGetUserInfoFailure will be 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // called on the consumer on the original thread. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartGetUserInfo(const std::string& lsid); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a MergeSession request to pre-login the user with the given 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // credentials. 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a MergeSession request to fill the browsing cookie jar with 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // credentials represented by the account whose uber-auth token is 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |uber_token|. This method will modify the cookies of the current profile. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either OnMergeSessionSuccess or OnMergeSessionFailure will be 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // called on the consumer on the original thread. 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartMergeSession(const std::string& uber_token); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a request to exchange an OAuthLogin-scoped oauth2 access token for an 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // uber-auth token. The returned token can be used with the method 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // StartMergeSession(). 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either OnUberAuthTokenSuccess or OnUberAuthTokenFailure will be 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // called on the consumer on the original thread. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartTokenFetchForUberAuthExchange(const std::string& access_token); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start a request to exchange an OAuthLogin-scoped oauth2 access token for a 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ClientLogin-style service tokens. The response to this request is the 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // same as the response to a ClientLogin request, except that captcha 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // challenges are never issued. 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Either OnClientLoginSuccess or OnClientLoginFailure will be 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // called on the consumer on the original thread. If |service| is empty, 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the call will attempt to fetch uber auth token. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartOAuthLogin(const std::string& access_token, 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& service); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Implementation of net::URLFetcherDelegate 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // StartClientLogin been called && results not back yet? 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool HasPendingFetch(); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stop any URL fetches in progress. 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void CancelRequest(); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // From a URLFetcher result, generate an appropriate error. 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // From the API documentation, both IssueAuthToken and ClientLogin have 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the same error returns. 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static GoogleServiceAuthError GenerateOAuthLoginError( 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& data, 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLRequestStatus& status); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ClientLogin body constants that don't change 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kCookiePersistence[]; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kAccountTypeHostedOrGoogle[]; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kAccountTypeGoogle[]; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The format of the POST body for ClientLogin. 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kClientLoginFormat[]; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The format of said POST body when CAPTCHA token & answer are specified. 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kClientLoginCaptchaFormat[]; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The format of the POST body for IssueAuthToken. 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kIssueAuthTokenFormat[]; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The format of the POST body to get OAuth2 auth code from auth token. 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kClientLoginToOAuth2BodyFormat[]; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The format of the POST body to get OAuth2 token pair from auth code. 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kOAuth2CodeToTokenPairBodyFormat[]; 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // The format of the POST body to revoke an OAuth2 token. 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) static const char kOAuth2RevokeTokenBodyFormat[]; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The format of the POST body for GetUserInfo. 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kGetUserInfoFormat[]; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The format of the POST body for MergeSession. 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kMergeSessionFormat[]; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The format of the URL for UberAuthToken. 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kUberAuthTokenURLFormat[]; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The format of the body for OAuthLogin. 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kOAuthLoginFormat[]; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Constants for parsing ClientLogin errors. 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kAccountDeletedError[]; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kAccountDeletedErrorCode[]; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kAccountDisabledError[]; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kAccountDisabledErrorCode[]; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kBadAuthenticationError[]; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kBadAuthenticationErrorCode[]; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kCaptchaError[]; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kCaptchaErrorCode[]; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kServiceUnavailableError[]; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kServiceUnavailableErrorCode[]; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kErrorParam[]; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kErrorUrlParam[]; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kCaptchaUrlParam[]; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kCaptchaTokenParam[]; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Constants for parsing ClientOAuth errors. 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kNeedsAdditional[]; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kCaptcha[]; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kTwoFactor[]; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Constants for request/response for OAuth2 requests. 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kAuthHeaderFormat[]; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kOAuthHeaderFormat[]; 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static const char kOAuth2BearerHeaderFormat[]; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kClientLoginToOAuth2CookiePartSecure[]; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kClientLoginToOAuth2CookiePartHttpOnly[]; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kClientLoginToOAuth2CookiePartCodePrefix[]; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kClientLoginToOAuth2CookiePartCodePrefixLength; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Process the results of a ClientLogin fetch. 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnClientLoginFetched(const std::string& data, 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLRequestStatus& status, 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int response_code); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnIssueAuthTokenFetched(const std::string& data, 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLRequestStatus& status, 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int response_code); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnClientLoginToOAuth2Fetched(const std::string& data, 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::ResponseCookies& cookies, 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLRequestStatus& status, 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int response_code); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnOAuth2TokenPairFetched(const std::string& data, 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLRequestStatus& status, 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int response_code); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void OnOAuth2RevokeTokenFetched(const std::string& data, 253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const net::URLRequestStatus& status, 254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int response_code); 255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnGetUserInfoFetched(const std::string& data, 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLRequestStatus& status, 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int response_code); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnMergeSessionFetched(const std::string& data, 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLRequestStatus& status, 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int response_code); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnUberAuthTokenFetch(const std::string& data, 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLRequestStatus& status, 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int response_code); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnOAuthLoginFetched(const std::string& data, 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLRequestStatus& status, 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int response_code); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Tokenize the results of a ClientLogin fetch. 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void ParseClientLoginResponse(const std::string& data, 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* sid, 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* lsid, 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* token); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void ParseClientLoginFailure(const std::string& data, 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* error, 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* error_url, 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* captcha_url, 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* captcha_token); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Parse ClientLogin to OAuth2 response. 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool ParseClientLoginToOAuth2Response( 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::ResponseCookies& cookies, 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* auth_code); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool ParseClientLoginToOAuth2Cookie(const std::string& cookie, 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* auth_code); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Is this a special case Gaia error for TwoFactor auth? 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool IsSecondFactorSuccess(const std::string& alleged_error); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Given parameters, create a ClientLogin request body. 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static std::string MakeClientLoginBody( 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& username, 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& password, 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& source, 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* const service, 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& login_token, 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& login_captcha, 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HostedAccountsSetting allow_hosted_accounts); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Supply the sid / lsid returned from ClientLogin in order to 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // request a long lived auth token for a service. 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static std::string MakeIssueAuthTokenBody(const std::string& sid, 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& lsid, 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* const service); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create body to get OAuth2 auth code. 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static std::string MakeGetAuthCodeBody(); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Given auth code, create body to get OAuth2 token pair. 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static std::string MakeGetTokenPairBody(const std::string& auth_code); 313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Given an OAuth2 token, create body to revoke the token. 314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string MakeRevokeTokenBody(const std::string& auth_token); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Supply the lsid returned from ClientLogin in order to fetch 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // user information. 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static std::string MakeGetUserInfoBody(const std::string& lsid); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Supply the authentication token returned from StartIssueAuthToken. 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static std::string MakeMergeSessionBody(const std::string& auth_token, 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& continue_url, 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& source); 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static std::string MakeGetAuthCodeHeader(const std::string& auth_token); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static std::string MakeOAuthLoginBody(const std::string& service, 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& source); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a fetcher usable for making any Gaia request. |body| is used 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as the body of the POST request sent to GAIA. Any strings listed in 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |headers| are added as extra HTTP headers in the request. 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |load_flags| are passed to directly to net::URLFetcher::Create() when 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // creating the URL fetcher. 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static net::URLFetcher* CreateGaiaFetcher( 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequestContextGetter* getter, 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& body, 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& headers, 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& gaia_gurl, 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int load_flags, 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLFetcherDelegate* delegate); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // From a URLFetcher result, generate an appropriate error. 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // From the API documentation, both IssueAuthToken and ClientLogin have 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the same error returns. 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static GoogleServiceAuthError GenerateAuthError( 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& data, 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLRequestStatus& status); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These fields are common to GaiaAuthFetcher, same every request 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GaiaAuthConsumer* const consumer_; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequestContextGetter* const getter_; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string source_; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL client_login_gurl_; 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL issue_auth_token_gurl_; 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL oauth2_token_gurl_; 357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const GURL oauth2_revoke_gurl_; 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL get_user_info_gurl_; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL merge_session_gurl_; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL uberauth_token_gurl_; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL oauth_login_gurl_; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // While a fetch is going on: 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<net::URLFetcher> fetcher_; 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL client_login_to_oauth2_gurl_; 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string request_body_; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string requested_service_; // Currently tracked for IssueAuthToken only. 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool fetch_pending_; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class GaiaAuthFetcherTest; 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CaptchaParse); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDeletedError); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDisabledError); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, BadAuthenticationError); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, IncomprehensibleError); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ServiceUnavailableError); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CheckNormalErrorCode); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CheckTwoFactorResponse); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, LoginNetFailure); 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseClientLoginToOAuth2Response); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ParseOAuth2TokenPairResponse); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthSuccess); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthWithQuote); 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthChallengeSuccess); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthChallengeQuote); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(GaiaAuthFetcher); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // GOOGLE_APIS_GAIA_GAIA_AUTH_FETCHER_H_ 392