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 "googleurl/src/gurl.h"
16 #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 // This will later be hidden behind an auth service which caches
49 GaiaAuthFetcher(GaiaAuthConsumer
* consumer
,
50 const std::string
& source
,
51 net::URLRequestContextGetter
* getter
);
52 virtual ~GaiaAuthFetcher();
54 // Start a request to obtain the SID and LSID cookies for the the account
55 // identified by |username| and |password|. If |service| is not null or
56 // empty, then also obtains a service token for specified service.
58 // If this is a second call because of captcha challenge, then the
59 // |login_token| and |login_captcha| arugment should correspond to the
60 // solution of the challenge.
62 // Either OnClientLoginSuccess or OnClientLoginFailure will be
63 // called on the consumer on the original thread.
64 void StartClientLogin(const std::string
& username
,
65 const std::string
& password
,
66 const char* const service
,
67 const std::string
& login_token
,
68 const std::string
& login_captcha
,
69 HostedAccountsSetting allow_hosted_accounts
);
71 // Start a request to obtain service token for the the account identified by
72 // |sid| and |lsid| and the |service|.
74 // Either OnIssueAuthTokenSuccess or OnIssueAuthTokenFailure will be
75 // called on the consumer on the original thread.
76 void StartIssueAuthToken(const std::string
& sid
,
77 const std::string
& lsid
,
78 const char* const service
);
80 // Start a request to obtain |service| token for the the account identified by
83 // Either OnIssueAuthTokenSuccess or OnIssueAuthTokenFailure will be
84 // called on the consumer on the original thread.
85 void StartTokenAuth(const std::string
& uber_token
,
86 const char* const service
);
88 // Start a request to obtain service token for the the account identified by
89 // |oauth2_access_token| and the |service|.
91 // Either OnIssueAuthTokenSuccess or OnIssueAuthTokenFailure will be
92 // called on the consumer on the original thread.
93 void StartIssueAuthTokenForOAuth2(const std::string
& oauth2_access_token
,
94 const char* const service
);
96 // Start a request to exchange an "lso" service token given by |auth_token|
97 // for an OAuthLogin-scoped oauth2 token.
99 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
100 // called on the consumer on the original thread.
101 void StartLsoForOAuthLoginTokenExchange(const std::string
& auth_token
);
103 // Start a request to revoke |auth_token|.
105 // Either OnRevokeOAuth2TokenSuccess or OnRevokeOAuth2TokenSuccess will be
106 // called on the consumer on the original thread.
107 void StartRevokeOAuth2Token(const std::string
& auth_token
);
109 // Start a request to exchange the cookies of a signed-in user session
110 // for an OAuthLogin-scoped oauth2 token. In the case of a session with
111 // multiple accounts signed in, |session_index| indicate the which of accounts
112 // within the session.
114 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
115 // called on the consumer on the original thread.
116 void StartCookieForOAuthLoginTokenExchange(const std::string
& session_index
);
118 // Start a request to exchange the authorization code for an OAuthLogin-scoped
121 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
122 // called on the consumer on the original thread.
123 void StartAuthCodeForOAuth2TokenExchange(const std::string
& auth_code
);
125 // Start a request to get user info for the account identified by |lsid|.
127 // Either OnGetUserInfoSuccess or OnGetUserInfoFailure will be
128 // called on the consumer on the original thread.
129 void StartGetUserInfo(const std::string
& lsid
);
131 // Start a MergeSession request to pre-login the user with the given
134 // Start a MergeSession request to fill the browsing cookie jar with
135 // credentials represented by the account whose uber-auth token is
136 // |uber_token|. This method will modify the cookies of the current profile.
138 // Either OnMergeSessionSuccess or OnMergeSessionFailure will be
139 // called on the consumer on the original thread.
140 void StartMergeSession(const std::string
& uber_token
);
142 // Start a request to exchange an OAuthLogin-scoped oauth2 access token for an
143 // uber-auth token. The returned token can be used with the method
144 // StartMergeSession().
146 // Either OnUberAuthTokenSuccess or OnUberAuthTokenFailure will be
147 // called on the consumer on the original thread.
148 void StartTokenFetchForUberAuthExchange(const std::string
& access_token
);
150 // Start a request to obtain an OAuth2 token for the account identified by
151 // |username| and |password|. |scopes| is a list of oauth scopes that
152 // indicate the access permerssions to assign to the returned token.
153 // |persistent_id| is an optional client identifier used to identify this
154 // particular chrome instances, which may reduce the chance of a challenge.
155 // |locale| will be used to format messages to be presented to the user in
156 // challenges, if needed.
158 // If the request cannot complete due to a challenge, the
159 // GoogleServiceAuthError will indicate the type of challenge required:
160 // either CAPTCHA_REQUIRED or TWO_FACTOR.
162 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
163 // called on the consumer on the original thread.
164 void StartClientOAuth(const std::string
& username
,
165 const std::string
& password
,
166 const std::vector
<std::string
>& scopes
,
167 const std::string
& persistent_id
,
168 const std::string
& locale
);
170 // Start a challenge response to obtain an OAuth2 token. This method is
171 // called after a challenge response is issued from a previous call to
172 // StartClientOAuth(). The |type| and |token| arguments come from the
173 // error response to StartClientOAuth(), while the |solution| argument
174 // represents the answer from the user for the partocular challenge.
176 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
177 // called on the consumer on the original thread.
178 void StartClientOAuthChallengeResponse(GoogleServiceAuthError::State type
,
179 const std::string
& token
,
180 const std::string
& solution
);
182 // Start a request to exchange an OAuthLogin-scoped oauth2 access token for a
183 // ClientLogin-style service tokens. The response to this request is the
184 // same as the response to a ClientLogin request, except that captcha
185 // challenges are never issued.
187 // Either OnClientLoginSuccess or OnClientLoginFailure will be
188 // called on the consumer on the original thread. If |service| is empty,
189 // the call will attempt to fetch uber auth token.
190 void StartOAuthLogin(const std::string
& access_token
,
191 const std::string
& service
);
193 // Implementation of net::URLFetcherDelegate
194 virtual void OnURLFetchComplete(const net::URLFetcher
* source
) OVERRIDE
;
196 // StartClientLogin been called && results not back yet?
197 bool HasPendingFetch();
199 // Stop any URL fetches in progress.
200 void CancelRequest();
202 // From a URLFetcher result, generate an appropriate error.
203 // From the API documentation, both IssueAuthToken and ClientLogin have
204 // the same error returns.
205 static GoogleServiceAuthError
GenerateOAuthLoginError(
206 const std::string
& data
,
207 const net::URLRequestStatus
& status
);
210 // ClientLogin body constants that don't change
211 static const char kCookiePersistence
[];
212 static const char kAccountTypeHostedOrGoogle
[];
213 static const char kAccountTypeGoogle
[];
215 // The format of the POST body for ClientLogin.
216 static const char kClientLoginFormat
[];
217 // The format of said POST body when CAPTCHA token & answer are specified.
218 static const char kClientLoginCaptchaFormat
[];
219 // The format of the POST body for IssueAuthToken.
220 static const char kIssueAuthTokenFormat
[];
221 // The format of the POST body to get OAuth2 auth code from auth token.
222 static const char kClientLoginToOAuth2BodyFormat
[];
223 // The format of the POST body to get OAuth2 token pair from auth code.
224 static const char kOAuth2CodeToTokenPairBodyFormat
[];
225 // The format of the POST body to revoke an OAuth2 token.
226 static const char kOAuth2RevokeTokenBodyFormat
[];
227 // The format of the POST body for GetUserInfo.
228 static const char kGetUserInfoFormat
[];
229 // The format of the POST body for MergeSession.
230 static const char kMergeSessionFormat
[];
231 // The format of the URL for UberAuthToken.
232 static const char kUberAuthTokenURLFormat
[];
233 // The format of the body for OAuthLogin.
234 static const char kOAuthLoginFormat
[];
236 // Constants for parsing ClientLogin errors.
237 static const char kAccountDeletedError
[];
238 static const char kAccountDeletedErrorCode
[];
239 static const char kAccountDisabledError
[];
240 static const char kAccountDisabledErrorCode
[];
241 static const char kBadAuthenticationError
[];
242 static const char kBadAuthenticationErrorCode
[];
243 static const char kCaptchaError
[];
244 static const char kCaptchaErrorCode
[];
245 static const char kServiceUnavailableError
[];
246 static const char kServiceUnavailableErrorCode
[];
247 static const char kErrorParam
[];
248 static const char kErrorUrlParam
[];
249 static const char kCaptchaUrlParam
[];
250 static const char kCaptchaTokenParam
[];
252 // Constants for parsing ClientOAuth errors.
253 static const char kNeedsAdditional
[];
254 static const char kCaptcha
[];
255 static const char kTwoFactor
[];
257 // Constants for request/response for OAuth2 requests.
258 static const char kAuthHeaderFormat
[];
259 static const char kOAuthHeaderFormat
[];
260 static const char kOAuth2BearerHeaderFormat
[];
261 static const char kClientLoginToOAuth2CookiePartSecure
[];
262 static const char kClientLoginToOAuth2CookiePartHttpOnly
[];
263 static const char kClientLoginToOAuth2CookiePartCodePrefix
[];
264 static const int kClientLoginToOAuth2CookiePartCodePrefixLength
;
266 // Process the results of a ClientLogin fetch.
267 void OnClientLoginFetched(const std::string
& data
,
268 const net::URLRequestStatus
& status
,
271 void OnIssueAuthTokenFetched(const std::string
& data
,
272 const net::URLRequestStatus
& status
,
275 void OnClientLoginToOAuth2Fetched(const std::string
& data
,
276 const net::ResponseCookies
& cookies
,
277 const net::URLRequestStatus
& status
,
280 void OnOAuth2TokenPairFetched(const std::string
& data
,
281 const net::URLRequestStatus
& status
,
284 void OnOAuth2RevokeTokenFetched(const std::string
& data
,
285 const net::URLRequestStatus
& status
,
288 void OnGetUserInfoFetched(const std::string
& data
,
289 const net::URLRequestStatus
& status
,
292 void OnMergeSessionFetched(const std::string
& data
,
293 const net::URLRequestStatus
& status
,
296 void OnUberAuthTokenFetch(const std::string
& data
,
297 const net::URLRequestStatus
& status
,
300 void OnClientOAuthFetched(const std::string
& data
,
301 const net::URLRequestStatus
& status
,
304 void OnOAuthLoginFetched(const std::string
& data
,
305 const net::URLRequestStatus
& status
,
308 // Tokenize the results of a ClientLogin fetch.
309 static void ParseClientLoginResponse(const std::string
& data
,
314 static void ParseClientLoginFailure(const std::string
& data
,
316 std::string
* error_url
,
317 std::string
* captcha_url
,
318 std::string
* captcha_token
);
320 // Parse ClientLogin to OAuth2 response.
321 static bool ParseClientLoginToOAuth2Response(
322 const net::ResponseCookies
& cookies
,
323 std::string
* auth_code
);
325 static bool ParseClientLoginToOAuth2Cookie(const std::string
& cookie
,
326 std::string
* auth_code
);
328 static GoogleServiceAuthError
GenerateClientOAuthError(
329 const std::string
& data
,
330 const net::URLRequestStatus
& status
);
332 // Is this a special case Gaia error for TwoFactor auth?
333 static bool IsSecondFactorSuccess(const std::string
& alleged_error
);
335 // Given parameters, create a ClientLogin request body.
336 static std::string
MakeClientLoginBody(
337 const std::string
& username
,
338 const std::string
& password
,
339 const std::string
& source
,
340 const char* const service
,
341 const std::string
& login_token
,
342 const std::string
& login_captcha
,
343 HostedAccountsSetting allow_hosted_accounts
);
344 // Supply the sid / lsid returned from ClientLogin in order to
345 // request a long lived auth token for a service.
346 static std::string
MakeIssueAuthTokenBody(const std::string
& sid
,
347 const std::string
& lsid
,
348 const char* const service
);
349 // Create body to get OAuth2 auth code.
350 static std::string
MakeGetAuthCodeBody();
351 // Given auth code, create body to get OAuth2 token pair.
352 static std::string
MakeGetTokenPairBody(const std::string
& auth_code
);
353 // Given an OAuth2 token, create body to revoke the token.
354 std::string
MakeRevokeTokenBody(const std::string
& auth_token
);
355 // Supply the lsid returned from ClientLogin in order to fetch
357 static std::string
MakeGetUserInfoBody(const std::string
& lsid
);
359 // Supply the authentication token returned from StartIssueAuthToken.
360 static std::string
MakeMergeSessionBody(const std::string
& auth_token
,
361 const std::string
& continue_url
,
362 const std::string
& source
);
364 static std::string
MakeGetAuthCodeHeader(const std::string
& auth_token
);
366 static std::string
MakeClientOAuthBody(const std::string
& username
,
367 const std::string
& password
,
368 const std::vector
<std::string
>& scopes
,
369 const std::string
& persistent_id
,
370 const std::string
& friendly_name
,
371 const std::string
& locale
);
373 static std::string
MakeClientOAuthChallengeResponseBody(
374 const std::string
& name
,
375 const std::string
& token
,
376 const std::string
& solution
);
378 static std::string
MakeOAuthLoginBody(const std::string
& service
,
379 const std::string
& source
);
381 // Create a fetcher usable for making any Gaia request. |body| is used
382 // as the body of the POST request sent to GAIA. Any strings listed in
383 // |headers| are added as extra HTTP headers in the request.
385 // |load_flags| are passed to directly to net::URLFetcher::Create() when
386 // creating the URL fetcher.
387 static net::URLFetcher
* CreateGaiaFetcher(
388 net::URLRequestContextGetter
* getter
,
389 const std::string
& body
,
390 const std::string
& headers
,
391 const GURL
& gaia_gurl
,
393 net::URLFetcherDelegate
* delegate
);
395 // From a URLFetcher result, generate an appropriate error.
396 // From the API documentation, both IssueAuthToken and ClientLogin have
397 // the same error returns.
398 static GoogleServiceAuthError
GenerateAuthError(
399 const std::string
& data
,
400 const net::URLRequestStatus
& status
);
402 // These fields are common to GaiaAuthFetcher, same every request
403 GaiaAuthConsumer
* const consumer_
;
404 net::URLRequestContextGetter
* const getter_
;
406 const GURL client_login_gurl_
;
407 const GURL issue_auth_token_gurl_
;
408 const GURL oauth2_token_gurl_
;
409 const GURL oauth2_revoke_gurl_
;
410 const GURL get_user_info_gurl_
;
411 const GURL merge_session_gurl_
;
412 const GURL uberauth_token_gurl_
;
413 const GURL client_oauth_gurl_
;
414 const GURL oauth_login_gurl_
;
416 // While a fetch is going on:
417 scoped_ptr
<net::URLFetcher
> fetcher_
;
418 GURL client_login_to_oauth2_gurl_
;
419 std::string request_body_
;
420 std::string requested_service_
; // Currently tracked for IssueAuthToken only.
423 friend class GaiaAuthFetcherTest
;
424 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, CaptchaParse
);
425 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, AccountDeletedError
);
426 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, AccountDisabledError
);
427 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, BadAuthenticationError
);
428 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, IncomprehensibleError
);
429 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, ServiceUnavailableError
);
430 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, CheckNormalErrorCode
);
431 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, CheckTwoFactorResponse
);
432 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, LoginNetFailure
);
433 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
,
434 ParseClientLoginToOAuth2Response
);
435 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, ParseOAuth2TokenPairResponse
);
436 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, ClientOAuthSuccess
);
437 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, ClientOAuthWithQuote
);
438 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, ClientOAuthChallengeSuccess
);
439 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest
, ClientOAuthChallengeQuote
);
441 DISALLOW_COPY_AND_ASSIGN(GaiaAuthFetcher
);
444 #endif // GOOGLE_APIS_GAIA_GAIA_AUTH_FETCHER_H_