gaia_auth_fetcher.h revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef GOOGLE_APIS_GAIA_GAIA_AUTH_FETCHER_H_
6#define GOOGLE_APIS_GAIA_GAIA_AUTH_FETCHER_H_
7
8#include <string>
9#include <vector>
10
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"
16#include "url/gurl.h"
17
18// Authenticate a user against the Google Accounts ClientLogin API
19// with various capabilities and return results to a GaiaAuthConsumer.
20//
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
23// that you like.
24//
25// This class can handle one request at a time on any thread. To parallelize
26// requests, create multiple GaiaAuthFetcher's.
27
28class GaiaAuthFetcherTest;
29
30namespace net {
31class URLFetcher;
32class URLRequestContextGetter;
33class URLRequestStatus;
34}
35
36class GaiaAuthFetcher : public net::URLFetcherDelegate {
37 public:
38  enum HostedAccountsSetting {
39    HostedAccountsAllowed,
40    HostedAccountsNotAllowed
41  };
42
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[];
46
47  // This will later be hidden behind an auth service which caches
48  // tokens.
49  GaiaAuthFetcher(GaiaAuthConsumer* consumer,
50                  const std::string& source,
51                  net::URLRequestContextGetter* getter);
52  virtual ~GaiaAuthFetcher();
53
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.
57  //
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.
61  //
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);
70
71  // Start a request to obtain service token for the the account identified by
72  // |sid| and |lsid| and the |service|.
73  //
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);
79
80  // Start a request to obtain |service| token for the the account identified by
81  // |uber_token|.
82  //
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);
87
88  // Start a request to obtain service token for the the account identified by
89  // |oauth2_access_token| and the |service|.
90  //
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);
95
96  // Start a request to exchange an "lso" service token given by |auth_token|
97  // for an OAuthLogin-scoped oauth2 token.
98  //
99  // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
100  // called on the consumer on the original thread.
101  void StartLsoForOAuthLoginTokenExchange(const std::string& auth_token);
102
103  // Start a request to revoke |auth_token|.
104  //
105  // OnOAuth2RevokeTokenCompleted will be called on the consumer on the original
106  // thread.
107  void StartRevokeOAuth2Token(const std::string& auth_token);
108
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.
113  //
114  // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
115  // called on the consumer on the original thread.
116  void StartCookieForOAuthLoginTokenExchange(const std::string& session_index);
117
118  // Start a request to exchange the cookies of a signed-in user session
119  // for an OAuthLogin-scoped oauth2 token. In the case of a session with
120  // multiple accounts signed in, |session_index| indicate the which of accounts
121  // within the session.
122  // Resulting refresh token is annotated on the server with |device_id|. Format
123  // of device_id on the server is at most 64 unicode characters.
124  //
125  // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
126  // called on the consumer on the original thread.
127  void StartCookieForOAuthLoginTokenExchangeWithDeviceId(
128      const std::string& session_index,
129      const std::string& device_id);
130
131  // Start a request to exchange the authorization code for an OAuthLogin-scoped
132  // oauth2 token.
133  //
134  // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
135  // called on the consumer on the original thread.
136  void StartAuthCodeForOAuth2TokenExchange(const std::string& auth_code);
137
138  // Start a request to get user info for the account identified by |lsid|.
139  //
140  // Either OnGetUserInfoSuccess or OnGetUserInfoFailure will be
141  // called on the consumer on the original thread.
142  void StartGetUserInfo(const std::string& lsid);
143
144  // Start a MergeSession request to pre-login the user with the given
145  // credentials.
146  //
147  // Start a MergeSession request to fill the browsing cookie jar with
148  // credentials represented by the account whose uber-auth token is
149  // |uber_token|.  This method will modify the cookies of the current profile.
150  //
151  // The |external_cc_result| string can specify the result of connetion checks
152  // for various google properties, and MergeSession will set cookies on those
153  // properties too if appropriate.  See StartGetCheckConnectionInfo() for
154  // details.  The string is a comma separated list of token/result pairs, where
155  // token and result are separated by a colon.  This string may be empty, in
156  // which case no specific handling is performed.
157  //
158  // Either OnMergeSessionSuccess or OnMergeSessionFailure will be
159  // called on the consumer on the original thread.
160  void StartMergeSession(const std::string& uber_token,
161                         const std::string& external_cc_result);
162
163  // Start a request to exchange an OAuthLogin-scoped oauth2 access token for an
164  // uber-auth token.  The returned token can be used with the method
165  // StartMergeSession().
166  //
167  // Either OnUberAuthTokenSuccess or OnUberAuthTokenFailure will be
168  // called on the consumer on the original thread.
169  void StartTokenFetchForUberAuthExchange(const std::string& access_token);
170
171  // Start a request to exchange an OAuthLogin-scoped oauth2 access token for a
172  // ClientLogin-style service tokens.  The response to this request is the
173  // same as the response to a ClientLogin request, except that captcha
174  // challenges are never issued.
175  //
176  // Either OnClientLoginSuccess or OnClientLoginFailure will be
177  // called on the consumer on the original thread. If |service| is empty,
178  // the call will attempt to fetch uber auth token.
179  void StartOAuthLogin(const std::string& access_token,
180                       const std::string& service);
181
182  // Starts a request to list the accounts in the GAIA cookie.
183  void StartListAccounts();
184
185  // Starts a request to get the list of URLs to check for connection info.
186  // Returns token/URL pairs to check, and the resulting status can be given to
187  // /MergeSession requests.
188  void StartGetCheckConnectionInfo();
189
190  // Implementation of net::URLFetcherDelegate
191  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
192
193  // StartClientLogin been called && results not back yet?
194  bool HasPendingFetch();
195
196  // Stop any URL fetches in progress.
197  void CancelRequest();
198
199  // From a URLFetcher result, generate an appropriate error.
200  // From the API documentation, both IssueAuthToken and ClientLogin have
201  // the same error returns.
202  static GoogleServiceAuthError GenerateOAuthLoginError(
203      const std::string& data,
204      const net::URLRequestStatus& status);
205
206 private:
207  // ClientLogin body constants that don't change
208  static const char kCookiePersistence[];
209  static const char kAccountTypeHostedOrGoogle[];
210  static const char kAccountTypeGoogle[];
211
212  // The format of the POST body for ClientLogin.
213  static const char kClientLoginFormat[];
214  // The format of said POST body when CAPTCHA token & answer are specified.
215  static const char kClientLoginCaptchaFormat[];
216  // The format of the POST body for IssueAuthToken.
217  static const char kIssueAuthTokenFormat[];
218  // The format of the POST body to get OAuth2 auth code from auth token.
219  static const char kClientLoginToOAuth2BodyFormat[];
220  // The format of the POST body to get OAuth2 auth code from auth token. This
221  // format is used for request annotated with device_id.
222  static const char kClientLoginToOAuth2WithDeviceTypeBodyFormat[];
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[];
235
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[];
251
252  // Constants for parsing ClientOAuth errors.
253  static const char kNeedsAdditional[];
254  static const char kCaptcha[];
255  static const char kTwoFactor[];
256
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 kDeviceIdHeaderFormat[];
262  static const char kClientLoginToOAuth2CookiePartSecure[];
263  static const char kClientLoginToOAuth2CookiePartHttpOnly[];
264  static const char kClientLoginToOAuth2CookiePartCodePrefix[];
265  static const int kClientLoginToOAuth2CookiePartCodePrefixLength;
266
267  // Process the results of a ClientLogin fetch.
268  void OnClientLoginFetched(const std::string& data,
269                            const net::URLRequestStatus& status,
270                            int response_code);
271
272  void OnIssueAuthTokenFetched(const std::string& data,
273                               const net::URLRequestStatus& status,
274                               int response_code);
275
276  void OnClientLoginToOAuth2Fetched(const std::string& data,
277                                    const net::ResponseCookies& cookies,
278                                    const net::URLRequestStatus& status,
279                                    int response_code);
280
281  void OnOAuth2TokenPairFetched(const std::string& data,
282                                const net::URLRequestStatus& status,
283                                int response_code);
284
285  void OnOAuth2RevokeTokenFetched(const std::string& data,
286                                  const net::URLRequestStatus& status,
287                                  int response_code);
288
289  void OnListAccountsFetched(const std::string& data,
290                             const net::URLRequestStatus& status,
291                             int response_code);
292
293  void OnGetUserInfoFetched(const std::string& data,
294                            const net::URLRequestStatus& status,
295                            int response_code);
296
297  void OnMergeSessionFetched(const std::string& data,
298                             const net::URLRequestStatus& status,
299                             int response_code);
300
301  void OnUberAuthTokenFetch(const std::string& data,
302                            const net::URLRequestStatus& status,
303                            int response_code);
304
305  void OnOAuthLoginFetched(const std::string& data,
306                           const net::URLRequestStatus& status,
307                           int response_code);
308
309  void OnGetCheckConnectionInfoFetched(const std::string& data,
310                                       const net::URLRequestStatus& status,
311                                       int response_code);
312
313  // Tokenize the results of a ClientLogin fetch.
314  static void ParseClientLoginResponse(const std::string& data,
315                                       std::string* sid,
316                                       std::string* lsid,
317                                       std::string* token);
318
319  static void ParseClientLoginFailure(const std::string& data,
320                                      std::string* error,
321                                      std::string* error_url,
322                                      std::string* captcha_url,
323                                      std::string* captcha_token);
324
325  // Parse ClientLogin to OAuth2 response.
326  static bool ParseClientLoginToOAuth2Response(
327      const net::ResponseCookies& cookies,
328      std::string* auth_code);
329
330  static bool ParseClientLoginToOAuth2Cookie(const std::string& cookie,
331                                             std::string* auth_code);
332
333  // Is this a special case Gaia error for TwoFactor auth?
334  static bool IsSecondFactorSuccess(const std::string& alleged_error);
335
336  // Given parameters, create a ClientLogin request body.
337  static std::string MakeClientLoginBody(
338      const std::string& username,
339      const std::string& password,
340      const std::string& source,
341      const char* const service,
342      const std::string& login_token,
343      const std::string& login_captcha,
344      HostedAccountsSetting allow_hosted_accounts);
345  // Supply the sid / lsid returned from ClientLogin in order to
346  // request a long lived auth token for a service.
347  static std::string MakeIssueAuthTokenBody(const std::string& sid,
348                                            const std::string& lsid,
349                                            const char* const service);
350  // Create body to get OAuth2 auth code.
351  static std::string MakeGetAuthCodeBody(bool include_device_type);
352  // Given auth code, create body to get OAuth2 token pair.
353  static std::string MakeGetTokenPairBody(const std::string& auth_code);
354  // Given an OAuth2 token, create body to revoke the token.
355  std::string MakeRevokeTokenBody(const std::string& auth_token);
356  // Supply the lsid returned from ClientLogin in order to fetch
357  // user information.
358  static std::string MakeGetUserInfoBody(const std::string& lsid);
359
360  // Supply the authentication token returned from StartIssueAuthToken.
361  static std::string MakeMergeSessionBody(const std::string& auth_token,
362                                          const std::string& external_cc_result,
363                                          const std::string& continue_url,
364                                          const std::string& source);
365
366  static std::string MakeGetAuthCodeHeader(const std::string& auth_token);
367
368  static std::string MakeOAuthLoginBody(const std::string& service,
369                                        const std::string& source);
370
371  // Create a fetcher usable for making any Gaia request.  |body| is used
372  // as the body of the POST request sent to GAIA.  Any strings listed in
373  // |headers| are added as extra HTTP headers in the request.
374  //
375  // |load_flags| are passed to directly to net::URLFetcher::Create() when
376  // creating the URL fetcher.
377  static net::URLFetcher* CreateGaiaFetcher(
378      net::URLRequestContextGetter* getter,
379      const std::string& body,
380      const std::string& headers,
381      const GURL& gaia_gurl,
382      int load_flags,
383      net::URLFetcherDelegate* delegate);
384
385  // From a URLFetcher result, generate an appropriate error.
386  // From the API documentation, both IssueAuthToken and ClientLogin have
387  // the same error returns.
388  static GoogleServiceAuthError GenerateAuthError(
389      const std::string& data,
390      const net::URLRequestStatus& status);
391
392  // These fields are common to GaiaAuthFetcher, same every request
393  GaiaAuthConsumer* const consumer_;
394  net::URLRequestContextGetter* const getter_;
395  std::string source_;
396  const GURL client_login_gurl_;
397  const GURL issue_auth_token_gurl_;
398  const GURL oauth2_token_gurl_;
399  const GURL oauth2_revoke_gurl_;
400  const GURL get_user_info_gurl_;
401  const GURL merge_session_gurl_;
402  const GURL uberauth_token_gurl_;
403  const GURL oauth_login_gurl_;
404  const GURL list_accounts_gurl_;
405  const GURL get_check_connection_info_url_;
406
407  // While a fetch is going on:
408  scoped_ptr<net::URLFetcher> fetcher_;
409  GURL client_login_to_oauth2_gurl_;
410  std::string request_body_;
411  std::string requested_service_; // Currently tracked for IssueAuthToken only.
412  bool fetch_pending_;
413
414  friend class GaiaAuthFetcherTest;
415  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CaptchaParse);
416  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDeletedError);
417  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDisabledError);
418  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, BadAuthenticationError);
419  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, IncomprehensibleError);
420  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ServiceUnavailableError);
421  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CheckNormalErrorCode);
422  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CheckTwoFactorResponse);
423  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, LoginNetFailure);
424  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest,
425      ParseClientLoginToOAuth2Response);
426  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ParseOAuth2TokenPairResponse);
427  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthSuccess);
428  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthWithQuote);
429  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthChallengeSuccess);
430  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthChallengeQuote);
431
432  DISALLOW_COPY_AND_ASSIGN(GaiaAuthFetcher);
433};
434
435#endif  // GOOGLE_APIS_GAIA_GAIA_AUTH_FETCHER_H_
436