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