1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef GOOGLE_APIS_GAIA_GAIA_AUTH_FETCHER_H_
6 #define GOOGLE_APIS_GAIA_GAIA_AUTH_FETCHER_H_
11 #include "base/gtest_prod_util.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "google_apis/gaia/gaia_auth_consumer.h"
14 #include "google_apis/gaia/google_service_auth_error.h"
15 #include "net/url_request/url_fetcher_delegate.h"
18 // Authenticate a user against the Google Accounts ClientLogin API
19 // with various capabilities and return results to a GaiaAuthConsumer.
21 // In the future, we will also issue auth tokens from this class.
22 // This class should be used on a single thread, but it can be whichever thread
25 // This class can handle one request at a time on any thread. To parallelize
26 // requests, create multiple GaiaAuthFetcher's.
28 class GaiaAuthFetcherTest
;
32 class URLRequestContextGetter
;
33 class URLRequestStatus
;
36 class GaiaAuthFetcher
: public net::URLFetcherDelegate
{
38 enum HostedAccountsSetting
{
39 HostedAccountsAllowed
,
40 HostedAccountsNotAllowed
43 // Magic string indicating that, while a second factor is still
44 // needed to complete authentication, the user provided the right password.
45 static const char kSecondFactor
[];
47 // Magic string indicating that though the user does not have Less Secure
48 // Apps enabled, the user provided the right password.
49 static const char kWebLoginRequired
[];
51 // This will later be hidden behind an auth service which caches
53 GaiaAuthFetcher(GaiaAuthConsumer
* consumer
,
54 const std::string
& source
,
55 net::URLRequestContextGetter
* getter
);
56 ~GaiaAuthFetcher() override
;
58 // Start a request to obtain the SID and LSID cookies for the the account
59 // identified by |username| and |password|. If |service| is not null or
60 // empty, then also obtains a service token for specified service.
62 // If this is a second call because of captcha challenge, then the
63 // |login_token| and |login_captcha| arugment should correspond to the
64 // solution of the challenge.
66 // Either OnClientLoginSuccess or OnClientLoginFailure will be
67 // called on the consumer on the original thread.
68 void StartClientLogin(const std::string
& username
,
69 const std::string
& password
,
70 const char* const service
,
71 const std::string
& login_token
,
72 const std::string
& login_captcha
,
73 HostedAccountsSetting allow_hosted_accounts
);
75 // Start a request to obtain service token for the the account identified by
76 // |sid| and |lsid| and the |service|.
78 // Either OnIssueAuthTokenSuccess or OnIssueAuthTokenFailure will be
79 // called on the consumer on the original thread.
80 void StartIssueAuthToken(const std::string
& sid
,
81 const std::string
& lsid
,
82 const char* const service
);
84 // Start a request to obtain |service| token for the the account identified by
87 // Either OnIssueAuthTokenSuccess or OnIssueAuthTokenFailure will be
88 // called on the consumer on the original thread.
89 void StartTokenAuth(const std::string
& uber_token
,
90 const char* const service
);
92 // Start a request to obtain service token for the the account identified by
93 // |oauth2_access_token| and the |service|.
95 // Either OnIssueAuthTokenSuccess or OnIssueAuthTokenFailure will be
96 // called on the consumer on the original thread.
97 void StartIssueAuthTokenForOAuth2(const std::string
& oauth2_access_token
,
98 const char* const service
);
100 // Start a request to revoke |auth_token|.
102 // OnOAuth2RevokeTokenCompleted will be called on the consumer on the original
104 void StartRevokeOAuth2Token(const std::string
& auth_token
);
106 // Start a request to exchange the cookies of a signed-in user session
107 // for an OAuthLogin-scoped oauth2 token. In the case of a session with
108 // multiple accounts signed in, |session_index| indicate the which of accounts
109 // within the session.
111 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
112 // called on the consumer on the original thread.
113 void StartCookieForOAuthLoginTokenExchange(const std::string
& session_index
);
115 // Start a request to exchange the cookies of a signed-in user session
116 // for an OAuthLogin-scoped oauth2 token. In the case of a session with
117 // multiple accounts signed in, |session_index| indicate the which of accounts
118 // within the session.
119 // Resulting refresh token is annotated on the server with |device_id|. Format
120 // of device_id on the server is at most 64 unicode characters.
122 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
123 // called on the consumer on the original thread.
124 void StartCookieForOAuthLoginTokenExchangeWithDeviceId(
125 const std::string
& session_index
,
126 const std::string
& device_id
);
128 // Start a request to exchange the authorization code for an OAuthLogin-scoped
131 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
132 // called on the consumer on the original thread.
133 void StartAuthCodeForOAuth2TokenExchange(const std::string
& auth_code
);
135 // Start a request to exchange the authorization code for an OAuthLogin-scoped
137 // Resulting refresh token is annotated on the server with |device_id|. Format
138 // of device_id on the server is at most 64 unicode characters.
140 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
141 // called on the consumer on the original thread.
142 void StartAuthCodeForOAuth2TokenExchangeWithDeviceId(
143 const std::string
& auth_code
,
144 const std::string
& device_id
);
146 // Start a request to get user info for the account identified by |lsid|.
148 // Either OnGetUserInfoSuccess or OnGetUserInfoFailure will be
149 // called on the consumer on the original thread.
150 void StartGetUserInfo(const std::string
& lsid
);
152 // Start a MergeSession request to pre-login the user with the given
155 // Start a MergeSession request to fill the browsing cookie jar with
156 // credentials represented by the account whose uber-auth token is
157 // |uber_token|. This method will modify the cookies of the current profile.
159 // The |external_cc_result| string can specify the result of connetion checks
160 // for various google properties, and MergeSession will set cookies on those
161 // properties too if appropriate. See StartGetCheckConnectionInfo() for
162 // details. The string is a comma separated list of token/result pairs, where
163 // token and result are separated by a colon. This string may be empty, in
164 // which case no specific handling is performed.
166 // Either OnMergeSessionSuccess or OnMergeSessionFailure will be
167 // called on the consumer on the original thread.
168 void StartMergeSession(const std::string
& uber_token
,
169 const std::string
& external_cc_result
);
171 // Start a request to exchange an OAuthLogin-scoped oauth2 access token for an
172 // uber-auth token. The returned token can be used with the method
173 // StartMergeSession().
175 // Either OnUberAuthTokenSuccess or OnUberAuthTokenFailure will be
176 // called on the consumer on the original thread.
177 void StartTokenFetchForUberAuthExchange(const std::string
& access_token
);
179 // Start a request to exchange an OAuthLogin-scoped oauth2 access token for a
180 // ClientLogin-style service tokens. The response to this request is the
181 // same as the response to a ClientLogin request, except that captcha
182 // challenges are never issued.
184 // Either OnClientLoginSuccess or OnClientLoginFailure will be
185 // called on the consumer on the original thread. If |service| is empty,
186 // the call will attempt to fetch uber auth token.
187 void StartOAuthLogin(const std::string
& access_token
,
188 const std::string
& service
);
190 // Starts a request to list the accounts in the GAIA cookie.
191 void StartListAccounts();
193 // Starts a request to log out the accounts in the GAIA cookie.
196 // Starts a request to get the list of URLs to check for connection info.
197 // Returns token/URL pairs to check, and the resulting status can be given to
198 // /MergeSession requests.
199 void StartGetCheckConnectionInfo();
201 // Starts listing any sessions that exist for the IDP. If all requested scopes
202 // have been approved by the session user, then a login hint is included in
204 void StartListIDPSessions(const std::string
& scopes
,
205 const std::string
& domain
);
207 // Generates an access token for the session, specifying the scopes and
209 void StartGetTokenResponse(const std::string
& scopes
,
210 const std::string
& domain
,
211 const std::string
& login_hint
);
213 // Implementation of net::URLFetcherDelegate
214 void OnURLFetchComplete(const net::URLFetcher
* source
) override
;
216 // StartClientLogin been called && results not back yet?
217 bool HasPendingFetch();
219 // Stop any URL fetches in progress.
220 virtual void CancelRequest();
222 // From a URLFetcher result, generate an appropriate error.
223 // From the API documentation, both IssueAuthToken and ClientLogin have
224 // the same error returns.
225 static GoogleServiceAuthError
GenerateOAuthLoginError(
226 const std::string
& data
,
227 const net::URLRequestStatus
& status
);
230 // Create and start |fetcher_|, used to make all Gaia request. |body| is
231 // used as the body of the POST request sent to GAIA. Any strings listed in
232 // |headers| are added as extra HTTP headers in the request.
234 // |load_flags| are passed to directly to net::URLFetcher::Create() when
235 // creating the URL fetcher.
237 // HasPendingFetch() should return false before calling this method, and will
238 // return true afterwards.
239 virtual void CreateAndStartGaiaFetcher(const std::string
& body
,
240 const std::string
& headers
,
241 const GURL
& gaia_gurl
,
244 // Dispatch the results of a request.
245 void DispatchFetchedRequest(const GURL
& url
,
246 const std::string
& data
,
247 const net::ResponseCookies
& cookies
,
248 const net::URLRequestStatus
& status
,
251 void SetPendingFetch(bool pending_fetch
);
254 // ClientLogin body constants that don't change
255 static const char kCookiePersistence
[];
256 static const char kAccountTypeHostedOrGoogle
[];
257 static const char kAccountTypeGoogle
[];
259 // The format of the POST body for ClientLogin.
260 static const char kClientLoginFormat
[];
261 // The format of said POST body when CAPTCHA token & answer are specified.
262 static const char kClientLoginCaptchaFormat
[];
263 // The format of the POST body for IssueAuthToken.
264 static const char kIssueAuthTokenFormat
[];
265 // The format of the query string to get OAuth2 auth code from auth token.
266 static const char kClientLoginToOAuth2URLFormat
[];
267 // The format of the POST body to get OAuth2 token pair from auth code.
268 static const char kOAuth2CodeToTokenPairBodyFormat
[];
269 // Additional param for the POST body to get OAuth2 token pair from auth code.
270 static const char kOAuth2CodeToTokenPairDeviceIdParam
[];
271 // The format of the POST body to revoke an OAuth2 token.
272 static const char kOAuth2RevokeTokenBodyFormat
[];
273 // The format of the POST body for GetUserInfo.
274 static const char kGetUserInfoFormat
[];
275 // The format of the POST body for MergeSession.
276 static const char kMergeSessionFormat
[];
277 // The format of the URL for UberAuthToken.
278 static const char kUberAuthTokenURLFormat
[];
279 // The format of the body for OAuthLogin.
280 static const char kOAuthLoginFormat
[];
282 // Constants for parsing ClientLogin errors.
283 static const char kAccountDeletedError
[];
284 static const char kAccountDeletedErrorCode
[];
285 static const char kAccountDisabledError
[];
286 static const char kAccountDisabledErrorCode
[];
287 static const char kBadAuthenticationError
[];
288 static const char kBadAuthenticationErrorCode
[];
289 static const char kCaptchaError
[];
290 static const char kCaptchaErrorCode
[];
291 static const char kServiceUnavailableError
[];
292 static const char kServiceUnavailableErrorCode
[];
293 static const char kErrorParam
[];
294 static const char kErrorUrlParam
[];
295 static const char kCaptchaUrlParam
[];
296 static const char kCaptchaTokenParam
[];
298 // Constants for parsing ClientOAuth errors.
299 static const char kNeedsAdditional
[];
300 static const char kCaptcha
[];
301 static const char kTwoFactor
[];
303 // Constants for request/response for OAuth2 requests.
304 static const char kAuthHeaderFormat
[];
305 static const char kOAuthHeaderFormat
[];
306 static const char kOAuth2BearerHeaderFormat
[];
307 static const char kDeviceIdHeaderFormat
[];
308 static const char kClientLoginToOAuth2CookiePartSecure
[];
309 static const char kClientLoginToOAuth2CookiePartHttpOnly
[];
310 static const char kClientLoginToOAuth2CookiePartCodePrefix
[];
311 static const int kClientLoginToOAuth2CookiePartCodePrefixLength
;
313 // Process the results of a ClientLogin fetch.
314 void OnClientLoginFetched(const std::string
& data
,
315 const net::URLRequestStatus
& status
,
318 void OnIssueAuthTokenFetched(const std::string
& data
,
319 const net::URLRequestStatus
& status
,
322 void OnClientLoginToOAuth2Fetched(const std::string
& data
,
323 const net::ResponseCookies
& cookies
,
324 const net::URLRequestStatus
& status
,
327 void OnOAuth2TokenPairFetched(const std::string
& data
,
328 const net::URLRequestStatus
& status
,
331 void OnOAuth2RevokeTokenFetched(const std::string
& data
,
332 const net::URLRequestStatus
& status
,
335 void OnListAccountsFetched(const std::string
& data
,
336 const net::URLRequestStatus
& status
,
339 void OnLogOutFetched(const std::string
& data
,
340 const net::URLRequestStatus
& status
,
343 void OnGetUserInfoFetched(const std::string
& data
,
344 const net::URLRequestStatus
& status
,
347 void OnMergeSessionFetched(const std::string
& data
,
348 const net::URLRequestStatus
& status
,
351 void OnUberAuthTokenFetch(const std::string
& data
,
352 const net::URLRequestStatus
& status
,
355 void OnOAuthLoginFetched(const std::string
& data
,
356 const net::URLRequestStatus
& status
,
359 void OnGetCheckConnectionInfoFetched(const std::string
& data
,
360 const net::URLRequestStatus
& status
,
363 void OnListIdpSessionsFetched(const std::string
& data
,
364 const net::URLRequestStatus
& status
,
367 void OnGetTokenResponseFetched(const std::string
& data
,
368 const net::URLRequestStatus
& status
,
371 // Tokenize the results of a ClientLogin fetch.
372 static void ParseClientLoginResponse(const std::string
& data
,
377 static void ParseClientLoginFailure(const std::string
& data
,
379 std::string
* error_url
,
380 std::string
* captcha_url
,
381 std::string
* captcha_token
);
383 // Parse ClientLogin to OAuth2 response.
384 static bool ParseClientLoginToOAuth2Response(
385 const net::ResponseCookies
& cookies
,
386 std::string
* auth_code
);
388 static bool ParseClientLoginToOAuth2Cookie(const std::string
& cookie
,
389 std::string
* auth_code
);
391 static bool ParseListIdpSessionsResponse(const std::string
& data
,
392 std::string
* login_hint
);
394 // Is this a special case Gaia error for TwoFactor auth?
395 static bool IsSecondFactorSuccess(const std::string
& alleged_error
);
397 // Is this a special case Gaia error for Less Secure Apps?
398 static bool IsWebLoginRequiredSuccess(const std::string
& alleged_error
);
400 // Given parameters, create a ClientLogin request body.
401 static std::string
MakeClientLoginBody(
402 const std::string
& username
,
403 const std::string
& password
,
404 const std::string
& source
,
405 const char* const service
,
406 const std::string
& login_token
,
407 const std::string
& login_captcha
,
408 HostedAccountsSetting allow_hosted_accounts
);
409 // Supply the sid / lsid returned from ClientLogin in order to
410 // request a long lived auth token for a service.
411 static std::string
MakeIssueAuthTokenBody(const std::string
& sid
,
412 const std::string
& lsid
,
413 const char* const service
);
414 // Given auth code and device ID (optional), create body to get OAuth2 token
416 static std::string
MakeGetTokenPairBody(const std::string
& auth_code
,
417 const std::string
& device_id
);
418 // Given an OAuth2 token, create body to revoke the token.
419 std::string
MakeRevokeTokenBody(const std::string
& auth_token
);
420 // Supply the lsid returned from ClientLogin in order to fetch
422 static std::string
MakeGetUserInfoBody(const std::string
& lsid
);
424 // Supply the authentication token returned from StartIssueAuthToken.
425 static std::string
MakeMergeSessionBody(const std::string
& auth_token
,
426 const std::string
& external_cc_result
,
427 const std::string
& continue_url
,
428 const std::string
& source
);
430 static std::string
MakeGetAuthCodeHeader(const std::string
& auth_token
);
432 static std::string
MakeOAuthLoginBody(const std::string
& service
,
433 const std::string
& source
);
435 static std::string
MakeListIDPSessionsBody(const std::string
& scopes
,
436 const std::string
& domain
);
438 static std::string
MakeGetTokenResponseBody(const std::string
& scopes
,
439 const std::string
& domain
,
440 const std::string
& login_hint
);
442 // From a URLFetcher result, generate an appropriate error.
443 // From the API documentation, both IssueAuthToken and ClientLogin have
444 // the same error returns.
445 static GoogleServiceAuthError
GenerateAuthError(
446 const std::string
& data
,
447 const net::URLRequestStatus
& status
);
449 // These fields are common to GaiaAuthFetcher, same every request.
450 GaiaAuthConsumer
* const consumer_
;
451 net::URLRequestContextGetter
* const getter_
;
453 const GURL client_login_gurl_
;
454 const GURL issue_auth_token_gurl_
;
455 const GURL oauth2_token_gurl_
;
456 const GURL oauth2_revoke_gurl_
;
457 const GURL get_user_info_gurl_
;
458 const GURL merge_session_gurl_
;
459 const GURL uberauth_token_gurl_
;
460 const GURL oauth_login_gurl_
;
461 const GURL list_accounts_gurl_
;
462 const GURL logout_gurl_
;
463 const GURL get_check_connection_info_url_
;
464 const GURL oauth2_iframe_url_
;
466 // While a fetch is going on:
467 scoped_ptr
<net::URLFetcher
> fetcher_
;
468 GURL client_login_to_oauth2_gurl_
;
469 std::string request_body_
;
470 std::string requested_service_
;
473 friend class GaiaAuthFetcherTest
;
474 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, CaptchaParse
);
475 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, AccountDeletedError
);
476 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, AccountDisabledError
);
477 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, BadAuthenticationError
);
478 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, IncomprehensibleError
);
479 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, ServiceUnavailableError
);
480 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, CheckNormalErrorCode
);
481 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, CheckTwoFactorResponse
);
482 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, LoginNetFailure
);
483 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
,
484 ParseClientLoginToOAuth2Response
);
485 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, ParseOAuth2TokenPairResponse
);
486 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, ClientOAuthSuccess
);
487 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, ClientOAuthWithQuote
);
488 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, ClientOAuthChallengeSuccess
);
489 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, ClientOAuthChallengeQuote
);
491 DISALLOW_COPY_AND_ASSIGN(GaiaAuthFetcher
);
494 #endif // GOOGLE_APIS_GAIA_GAIA_AUTH_FETCHER_H_