1// Copyright (c) 2011 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 CHROME_COMMON_NET_GAIA_GAIA_AUTH_FETCHER_H_
6#define CHROME_COMMON_NET_GAIA_GAIA_AUTH_FETCHER_H_
7#pragma once
8
9#include <string>
10
11#include "base/gtest_prod_util.h"
12#include "base/memory/scoped_ptr.h"
13#include "chrome/common/net/gaia/gaia_auth_consumer.h"
14#include "chrome/common/net/url_fetcher.h"
15#include "googleurl/src/gurl.h"
16
17// Authenticate a user against the Google Accounts ClientLogin API
18// with various capabilities and return results to a GaiaAuthConsumer.
19//
20// In the future, we will also issue auth tokens from this class.
21// This class should be used on a single thread, but it can be whichever thread
22// that you like.
23//
24// This class can handle one request at a time. To parallelize requests,
25// create multiple GaiaAuthFetcher's.
26
27class GaiaAuthFetcherTest;
28
29class GaiaAuthFetcher : public URLFetcher::Delegate {
30 public:
31  enum HostedAccountsSetting {
32    HostedAccountsAllowed,
33    HostedAccountsNotAllowed
34  };
35
36  // The URLs for different calls in the Google Accounts programmatic login API.
37  static const char kClientLoginUrl[];
38  static const char kIssueAuthTokenUrl[];
39  static const char kGetUserInfoUrl[];
40
41  // Magic string indicating that, while a second factor is still
42  // needed to complete authentication, the user provided the right password.
43  static const char kSecondFactor[];
44
45  // This will later be hidden behind an auth service which caches
46  // tokens.
47  GaiaAuthFetcher(GaiaAuthConsumer* consumer,
48                  const std::string& source,
49                  net::URLRequestContextGetter* getter);
50  virtual ~GaiaAuthFetcher();
51
52  // GaiaAuthConsumer will be called on the original thread
53  // after results come back. This class is thread agnostic.
54  // You can't make more than request at a time.
55  void StartClientLogin(const std::string& username,
56                        const std::string& password,
57                        const char* const service,
58                        const std::string& login_token,
59                        const std::string& login_captcha,
60                        HostedAccountsSetting allow_hosted_accounts);
61
62  // GaiaAuthConsumer will be called on the original thread
63  // after results come back. This class is thread agnostic.
64  // You can't make more than one request at a time.
65  void StartIssueAuthToken(const std::string& sid,
66                           const std::string& lsid,
67                           const char* const service);
68
69  // Start a request to get a particular key from user info.
70  // GaiaAuthConsumer will be called back on the same thread when
71  // results come back.
72  // You can't make more than one request at a time.
73  void StartGetUserInfo(const std::string& lsid,
74                        const std::string& info_key);
75
76  // Implementation of URLFetcher::Delegate
77  virtual void OnURLFetchComplete(const URLFetcher* source,
78                                  const GURL& url,
79                                  const net::URLRequestStatus& status,
80                                  int response_code,
81                                  const ResponseCookies& cookies,
82                                  const std::string& data);
83
84  // StartClientLogin been called && results not back yet?
85  bool HasPendingFetch();
86
87  // Stop any URL fetches in progress.
88  void CancelRequest();
89
90 private:
91  // ClientLogin body constants that don't change
92  static const char kCookiePersistence[];
93  static const char kAccountTypeHostedOrGoogle[];
94  static const char kAccountTypeGoogle[];
95
96  // The format of the POST body for ClientLogin.
97  static const char kClientLoginFormat[];
98  // The format of said POST body when CAPTCHA token & answer are specified.
99  static const char kClientLoginCaptchaFormat[];
100  // The format of the POST body for IssueAuthToken.
101  static const char kIssueAuthTokenFormat[];
102  // The format of the POSt body for GetUserInfo.
103  static const char kGetUserInfoFormat[];
104
105  // Constants for parsing ClientLogin errors.
106  static const char kAccountDeletedError[];
107  static const char kAccountDisabledError[];
108  static const char kBadAuthenticationError[];
109  static const char kCaptchaError[];
110  static const char kServiceUnavailableError[];
111  static const char kErrorParam[];
112  static const char kErrorUrlParam[];
113  static const char kCaptchaUrlParam[];
114  static const char kCaptchaTokenParam[];
115  static const char kCaptchaUrlPrefix[];
116
117  // Process the results of a ClientLogin fetch.
118  void OnClientLoginFetched(const std::string& data,
119                            const net::URLRequestStatus& status,
120                            int response_code);
121
122  void OnIssueAuthTokenFetched(const std::string& data,
123                               const net::URLRequestStatus& status,
124                               int response_code);
125
126  void OnGetUserInfoFetched(const std::string& data,
127                            const net::URLRequestStatus& status,
128                            int response_code);
129
130  // Tokenize the results of a ClientLogin fetch.
131  static void ParseClientLoginResponse(const std::string& data,
132                                       std::string* sid,
133                                       std::string* lsid,
134                                       std::string* token);
135
136  static void ParseClientLoginFailure(const std::string& data,
137                                      std::string* error,
138                                      std::string* error_url,
139                                      std::string* captcha_url,
140                                      std::string* captcha_token);
141
142  // From a URLFetcher result, generate an appropriate error.
143  // From the API documentation, both IssueAuthToken and ClientLogin have
144  // the same error returns.
145  static GoogleServiceAuthError GenerateAuthError(
146      const std::string& data,
147      const net::URLRequestStatus& status);
148
149  // Is this a special case Gaia error for TwoFactor auth?
150  static bool IsSecondFactorSuccess(const std::string& alleged_error);
151
152  // Given parameters, create a ClientLogin request body.
153  static std::string MakeClientLoginBody(
154      const std::string& username,
155      const std::string& password,
156      const std::string& source,
157      const char* const service,
158      const std::string& login_token,
159      const std::string& login_captcha,
160      HostedAccountsSetting allow_hosted_accounts);
161  // Supply the sid / lsid returned from ClientLogin in order to
162  // request a long lived auth token for a service.
163  static std::string MakeIssueAuthTokenBody(const std::string& sid,
164                                            const std::string& lsid,
165                                            const char* const service);
166  // Supply the lsid returned from ClientLogin in order to fetch
167  // user information.
168  static std::string MakeGetUserInfoBody(const std::string& lsid);
169
170  // Create a fetcher useable for making any Gaia request.
171  static URLFetcher* CreateGaiaFetcher(net::URLRequestContextGetter* getter,
172                                       const std::string& body,
173                                       const GURL& gaia_gurl_,
174                                       URLFetcher::Delegate* delegate);
175
176
177  // These fields are common to GaiaAuthFetcher, same every request
178  GaiaAuthConsumer* const consumer_;
179  net::URLRequestContextGetter* const getter_;
180  std::string source_;
181  const GURL client_login_gurl_;
182  const GURL issue_auth_token_gurl_;
183  const GURL get_user_info_gurl_;
184
185  // While a fetch is going on:
186  scoped_ptr<URLFetcher> fetcher_;
187  std::string request_body_;
188  std::string requested_service_;   // Currently tracked for IssueAuthToken only
189  std::string requested_info_key_;  // Currently tracked for GetUserInfo only
190  bool fetch_pending_;
191
192  friend class GaiaAuthFetcherTest;
193  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CaptchaParse);
194  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDeletedError);
195  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDisabledError);
196  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, BadAuthenticationError);
197  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, IncomprehensibleError);
198  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ServiceUnavailableError);
199  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CheckNormalErrorCode);
200  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CheckTwoFactorResponse);
201  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, LoginNetFailure);
202
203  DISALLOW_COPY_AND_ASSIGN(GaiaAuthFetcher);
204};
205
206#endif  // CHROME_COMMON_NET_GAIA_GAIA_AUTH_FETCHER_H_
207