gaia_auth_fetcher.h revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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  // Either OnRevokeOAuth2TokenSuccess or OnRevokeOAuth2TokenSuccess will be
106  // called on the consumer on the original 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 authorization code for an OAuthLogin-scoped
119  // oauth2 token.
120  //
121  // Either OnClientOAuthSuccess or OnClientOAuthFailure will be
122  // called on the consumer on the original thread.
123  void StartAuthCodeForOAuth2TokenExchange(const std::string& auth_code);
124
125  // Start a request to get user info for the account identified by |lsid|.
126  //
127  // Either OnGetUserInfoSuccess or OnGetUserInfoFailure will be
128  // called on the consumer on the original thread.
129  void StartGetUserInfo(const std::string& lsid);
130
131  // Start a MergeSession request to pre-login the user with the given
132  // credentials.
133  //
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.
137  //
138  // Either OnMergeSessionSuccess or OnMergeSessionFailure will be
139  // called on the consumer on the original thread.
140  void StartMergeSession(const std::string& uber_token);
141
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().
145  //
146  // Either OnUberAuthTokenSuccess or OnUberAuthTokenFailure will be
147  // called on the consumer on the original thread.
148  void StartTokenFetchForUberAuthExchange(const std::string& access_token);
149
150  // Start a request to exchange an OAuthLogin-scoped oauth2 access token for a
151  // ClientLogin-style service tokens.  The response to this request is the
152  // same as the response to a ClientLogin request, except that captcha
153  // challenges are never issued.
154  //
155  // Either OnClientLoginSuccess or OnClientLoginFailure will be
156  // called on the consumer on the original thread. If |service| is empty,
157  // the call will attempt to fetch uber auth token.
158  void StartOAuthLogin(const std::string& access_token,
159                       const std::string& service);
160
161  // Implementation of net::URLFetcherDelegate
162  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
163
164  // StartClientLogin been called && results not back yet?
165  bool HasPendingFetch();
166
167  // Stop any URL fetches in progress.
168  void CancelRequest();
169
170  // From a URLFetcher result, generate an appropriate error.
171  // From the API documentation, both IssueAuthToken and ClientLogin have
172  // the same error returns.
173  static GoogleServiceAuthError GenerateOAuthLoginError(
174      const std::string& data,
175      const net::URLRequestStatus& status);
176
177 private:
178  // ClientLogin body constants that don't change
179  static const char kCookiePersistence[];
180  static const char kAccountTypeHostedOrGoogle[];
181  static const char kAccountTypeGoogle[];
182
183  // The format of the POST body for ClientLogin.
184  static const char kClientLoginFormat[];
185  // The format of said POST body when CAPTCHA token & answer are specified.
186  static const char kClientLoginCaptchaFormat[];
187  // The format of the POST body for IssueAuthToken.
188  static const char kIssueAuthTokenFormat[];
189  // The format of the POST body to get OAuth2 auth code from auth token.
190  static const char kClientLoginToOAuth2BodyFormat[];
191  // The format of the POST body to get OAuth2 token pair from auth code.
192  static const char kOAuth2CodeToTokenPairBodyFormat[];
193  // The format of the POST body to revoke an OAuth2 token.
194  static const char kOAuth2RevokeTokenBodyFormat[];
195  // The format of the POST body for GetUserInfo.
196  static const char kGetUserInfoFormat[];
197  // The format of the POST body for MergeSession.
198  static const char kMergeSessionFormat[];
199  // The format of the URL for UberAuthToken.
200  static const char kUberAuthTokenURLFormat[];
201  // The format of the body for OAuthLogin.
202  static const char kOAuthLoginFormat[];
203
204  // Constants for parsing ClientLogin errors.
205  static const char kAccountDeletedError[];
206  static const char kAccountDeletedErrorCode[];
207  static const char kAccountDisabledError[];
208  static const char kAccountDisabledErrorCode[];
209  static const char kBadAuthenticationError[];
210  static const char kBadAuthenticationErrorCode[];
211  static const char kCaptchaError[];
212  static const char kCaptchaErrorCode[];
213  static const char kServiceUnavailableError[];
214  static const char kServiceUnavailableErrorCode[];
215  static const char kErrorParam[];
216  static const char kErrorUrlParam[];
217  static const char kCaptchaUrlParam[];
218  static const char kCaptchaTokenParam[];
219
220  // Constants for parsing ClientOAuth errors.
221  static const char kNeedsAdditional[];
222  static const char kCaptcha[];
223  static const char kTwoFactor[];
224
225  // Constants for request/response for OAuth2 requests.
226  static const char kAuthHeaderFormat[];
227  static const char kOAuthHeaderFormat[];
228  static const char kOAuth2BearerHeaderFormat[];
229  static const char kClientLoginToOAuth2CookiePartSecure[];
230  static const char kClientLoginToOAuth2CookiePartHttpOnly[];
231  static const char kClientLoginToOAuth2CookiePartCodePrefix[];
232  static const int kClientLoginToOAuth2CookiePartCodePrefixLength;
233
234  // Process the results of a ClientLogin fetch.
235  void OnClientLoginFetched(const std::string& data,
236                            const net::URLRequestStatus& status,
237                            int response_code);
238
239  void OnIssueAuthTokenFetched(const std::string& data,
240                               const net::URLRequestStatus& status,
241                               int response_code);
242
243  void OnClientLoginToOAuth2Fetched(const std::string& data,
244                                    const net::ResponseCookies& cookies,
245                                    const net::URLRequestStatus& status,
246                                    int response_code);
247
248  void OnOAuth2TokenPairFetched(const std::string& data,
249                                const net::URLRequestStatus& status,
250                                int response_code);
251
252  void OnOAuth2RevokeTokenFetched(const std::string& data,
253                                  const net::URLRequestStatus& status,
254                                  int response_code);
255
256  void OnGetUserInfoFetched(const std::string& data,
257                            const net::URLRequestStatus& status,
258                            int response_code);
259
260  void OnMergeSessionFetched(const std::string& data,
261                             const net::URLRequestStatus& status,
262                             int response_code);
263
264  void OnUberAuthTokenFetch(const std::string& data,
265                            const net::URLRequestStatus& status,
266                            int response_code);
267
268  void OnOAuthLoginFetched(const std::string& data,
269                           const net::URLRequestStatus& status,
270                           int response_code);
271
272  // Tokenize the results of a ClientLogin fetch.
273  static void ParseClientLoginResponse(const std::string& data,
274                                       std::string* sid,
275                                       std::string* lsid,
276                                       std::string* token);
277
278  static void ParseClientLoginFailure(const std::string& data,
279                                      std::string* error,
280                                      std::string* error_url,
281                                      std::string* captcha_url,
282                                      std::string* captcha_token);
283
284  // Parse ClientLogin to OAuth2 response.
285  static bool ParseClientLoginToOAuth2Response(
286      const net::ResponseCookies& cookies,
287      std::string* auth_code);
288
289  static bool ParseClientLoginToOAuth2Cookie(const std::string& cookie,
290                                             std::string* auth_code);
291
292  // Is this a special case Gaia error for TwoFactor auth?
293  static bool IsSecondFactorSuccess(const std::string& alleged_error);
294
295  // Given parameters, create a ClientLogin request body.
296  static std::string MakeClientLoginBody(
297      const std::string& username,
298      const std::string& password,
299      const std::string& source,
300      const char* const service,
301      const std::string& login_token,
302      const std::string& login_captcha,
303      HostedAccountsSetting allow_hosted_accounts);
304  // Supply the sid / lsid returned from ClientLogin in order to
305  // request a long lived auth token for a service.
306  static std::string MakeIssueAuthTokenBody(const std::string& sid,
307                                            const std::string& lsid,
308                                            const char* const service);
309  // Create body to get OAuth2 auth code.
310  static std::string MakeGetAuthCodeBody();
311  // Given auth code, create body to get OAuth2 token pair.
312  static std::string MakeGetTokenPairBody(const std::string& auth_code);
313  // Given an OAuth2 token, create body to revoke the token.
314  std::string MakeRevokeTokenBody(const std::string& auth_token);
315  // Supply the lsid returned from ClientLogin in order to fetch
316  // user information.
317  static std::string MakeGetUserInfoBody(const std::string& lsid);
318
319  // Supply the authentication token returned from StartIssueAuthToken.
320  static std::string MakeMergeSessionBody(const std::string& auth_token,
321                                       const std::string& continue_url,
322                                       const std::string& source);
323
324  static std::string MakeGetAuthCodeHeader(const std::string& auth_token);
325
326  static std::string MakeOAuthLoginBody(const std::string& service,
327                                        const std::string& source);
328
329  // Create a fetcher usable for making any Gaia request.  |body| is used
330  // as the body of the POST request sent to GAIA.  Any strings listed in
331  // |headers| are added as extra HTTP headers in the request.
332  //
333  // |load_flags| are passed to directly to net::URLFetcher::Create() when
334  // creating the URL fetcher.
335  static net::URLFetcher* CreateGaiaFetcher(
336      net::URLRequestContextGetter* getter,
337      const std::string& body,
338      const std::string& headers,
339      const GURL& gaia_gurl,
340      int load_flags,
341      net::URLFetcherDelegate* delegate);
342
343  // From a URLFetcher result, generate an appropriate error.
344  // From the API documentation, both IssueAuthToken and ClientLogin have
345  // the same error returns.
346  static GoogleServiceAuthError GenerateAuthError(
347      const std::string& data,
348      const net::URLRequestStatus& status);
349
350  // These fields are common to GaiaAuthFetcher, same every request
351  GaiaAuthConsumer* const consumer_;
352  net::URLRequestContextGetter* const getter_;
353  std::string source_;
354  const GURL client_login_gurl_;
355  const GURL issue_auth_token_gurl_;
356  const GURL oauth2_token_gurl_;
357  const GURL oauth2_revoke_gurl_;
358  const GURL get_user_info_gurl_;
359  const GURL merge_session_gurl_;
360  const GURL uberauth_token_gurl_;
361  const GURL oauth_login_gurl_;
362
363  // While a fetch is going on:
364  scoped_ptr<net::URLFetcher> fetcher_;
365  GURL client_login_to_oauth2_gurl_;
366  std::string request_body_;
367  std::string requested_service_; // Currently tracked for IssueAuthToken only.
368  bool fetch_pending_;
369
370  friend class GaiaAuthFetcherTest;
371  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CaptchaParse);
372  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDeletedError);
373  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDisabledError);
374  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, BadAuthenticationError);
375  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, IncomprehensibleError);
376  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ServiceUnavailableError);
377  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CheckNormalErrorCode);
378  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CheckTwoFactorResponse);
379  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, LoginNetFailure);
380  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest,
381      ParseClientLoginToOAuth2Response);
382  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ParseOAuth2TokenPairResponse);
383  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthSuccess);
384  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthWithQuote);
385  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthChallengeSuccess);
386  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthChallengeQuote);
387
388  DISALLOW_COPY_AND_ASSIGN(GaiaAuthFetcher);
389};
390
391#endif  // GOOGLE_APIS_GAIA_GAIA_AUTH_FETCHER_H_
392