gaia_auth_fetcher.h revision 5821806d5e7f356e8fa4b058a389a808ea183019
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 "googleurl/src/gurl.h" 16#include "net/url_request/url_fetcher_delegate.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|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 exchange an "lso" service token given by |auth_token| 81 // for an OAuthLogin-scoped oauth2 token. 82 // 83 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be 84 // called on the consumer on the original thread. 85 void StartLsoForOAuthLoginTokenExchange(const std::string& auth_token); 86 87 // Start a request to exchange the cookies of a signed-in user session 88 // for an OAuthLogin-scoped oauth2 token. In the case of a session with 89 // multiple accounts signed in, |session_index| indicate the which of accounts 90 // within the session. 91 // 92 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be 93 // called on the consumer on the original thread. 94 void StartCookieForOAuthLoginTokenExchange(const std::string& session_index); 95 96 // Start a request to get user info for the account identified by |lsid|. 97 // 98 // Either OnGetUserInfoSuccess or OnGetUserInfoFailure will be 99 // called on the consumer on the original thread. 100 void StartGetUserInfo(const std::string& lsid); 101 102 // Start a MergeSession request to pre-login the user with the given 103 // credentials. 104 // 105 // Start a MergeSession request to fill the browsing cookie jar with 106 // credentials represented by the account whose uber-auth token is 107 // |uber_token|. This method will modify the cookies of the current profile. 108 // 109 // Either OnMergeSessionSuccess or OnMergeSessionFailure will be 110 // called on the consumer on the original thread. 111 void StartMergeSession(const std::string& uber_token); 112 113 // Start a request to exchange an OAuthLogin-scoped oauth2 access token for an 114 // uber-auth token. The returned token can be used with the method 115 // StartMergeSession(). 116 // 117 // Either OnUberAuthTokenSuccess or OnUberAuthTokenFailure will be 118 // called on the consumer on the original thread. 119 void StartTokenFetchForUberAuthExchange(const std::string& access_token); 120 121 // Start a request to obtain an OAuth2 token for the account identified by 122 // |username| and |password|. |scopes| is a list of oauth scopes that 123 // indicate the access permerssions to assign to the returned token. 124 // |persistent_id| is an optional client identifier used to identify this 125 // particular chrome instances, which may reduce the chance of a challenge. 126 // |locale| will be used to format messages to be presented to the user in 127 // challenges, if needed. 128 // 129 // If the request cannot complete due to a challenge, the 130 // GoogleServiceAuthError will indicate the type of challenge required: 131 // either CAPTCHA_REQUIRED or TWO_FACTOR. 132 // 133 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be 134 // called on the consumer on the original thread. 135 void StartClientOAuth(const std::string& username, 136 const std::string& password, 137 const std::vector<std::string>& scopes, 138 const std::string& persistent_id, 139 const std::string& locale); 140 141 // Start a challenge response to obtain an OAuth2 token. This method is 142 // called after a challenge response is issued from a previous call to 143 // StartClientOAuth(). The |type| and |token| arguments come from the 144 // error response to StartClientOAuth(), while the |solution| argument 145 // represents the answer from the user for the partocular challenge. 146 // 147 // Either OnClientOAuthSuccess or OnClientOAuthFailure will be 148 // called on the consumer on the original thread. 149 void StartClientOAuthChallengeResponse(GoogleServiceAuthError::State type, 150 const std::string& token, 151 const std::string& solution); 152 153 // Start a request to exchange an OAuthLogin-scoped oauth2 access token for a 154 // ClientLogin-style service tokens. The response to this request is the 155 // same as the response to a ClientLogin request, except that captcha 156 // challenges are never issued. 157 // 158 // Either OnClientLoginSuccess or OnClientLoginFailure will be 159 // called on the consumer on the original thread. 160 void StartOAuthLogin(const std::string& access_token, 161 const std::string& service); 162 163 // Implementation of net::URLFetcherDelegate 164 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; 165 166 // StartClientLogin been called && results not back yet? 167 bool HasPendingFetch(); 168 169 // Stop any URL fetches in progress. 170 void CancelRequest(); 171 172 // From a URLFetcher result, generate an appropriate error. 173 // From the API documentation, both IssueAuthToken and ClientLogin have 174 // the same error returns. 175 static GoogleServiceAuthError GenerateOAuthLoginError( 176 const std::string& data, 177 const net::URLRequestStatus& status); 178 179 private: 180 // ClientLogin body constants that don't change 181 static const char kCookiePersistence[]; 182 static const char kAccountTypeHostedOrGoogle[]; 183 static const char kAccountTypeGoogle[]; 184 185 // The format of the POST body for ClientLogin. 186 static const char kClientLoginFormat[]; 187 // The format of said POST body when CAPTCHA token & answer are specified. 188 static const char kClientLoginCaptchaFormat[]; 189 // The format of the POST body for IssueAuthToken. 190 static const char kIssueAuthTokenFormat[]; 191 // The format of the POST body to get OAuth2 auth code from auth token. 192 static const char kClientLoginToOAuth2BodyFormat[]; 193 // The format of the POST body to get OAuth2 token pair from auth code. 194 static const char kOAuth2CodeToTokenPairBodyFormat[]; 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 kClientLoginToOAuth2CookiePartSecure[]; 229 static const char kClientLoginToOAuth2CookiePartHttpOnly[]; 230 static const char kClientLoginToOAuth2CookiePartCodePrefix[]; 231 static const int kClientLoginToOAuth2CookiePartCodePrefixLength; 232 233 // Process the results of a ClientLogin fetch. 234 void OnClientLoginFetched(const std::string& data, 235 const net::URLRequestStatus& status, 236 int response_code); 237 238 void OnIssueAuthTokenFetched(const std::string& data, 239 const net::URLRequestStatus& status, 240 int response_code); 241 242 void OnClientLoginToOAuth2Fetched(const std::string& data, 243 const net::ResponseCookies& cookies, 244 const net::URLRequestStatus& status, 245 int response_code); 246 247 void OnOAuth2TokenPairFetched(const std::string& data, 248 const net::URLRequestStatus& status, 249 int response_code); 250 251 void OnGetUserInfoFetched(const std::string& data, 252 const net::URLRequestStatus& status, 253 int response_code); 254 255 void OnMergeSessionFetched(const std::string& data, 256 const net::URLRequestStatus& status, 257 int response_code); 258 259 void OnUberAuthTokenFetch(const std::string& data, 260 const net::URLRequestStatus& status, 261 int response_code); 262 263 void OnClientOAuthFetched(const std::string& data, 264 const net::URLRequestStatus& status, 265 int response_code); 266 267 void OnOAuthLoginFetched(const std::string& data, 268 const net::URLRequestStatus& status, 269 int response_code); 270 271 // Tokenize the results of a ClientLogin fetch. 272 static void ParseClientLoginResponse(const std::string& data, 273 std::string* sid, 274 std::string* lsid, 275 std::string* token); 276 277 static void ParseClientLoginFailure(const std::string& data, 278 std::string* error, 279 std::string* error_url, 280 std::string* captcha_url, 281 std::string* captcha_token); 282 283 // Parse ClientLogin to OAuth2 response. 284 static bool ParseClientLoginToOAuth2Response( 285 const net::ResponseCookies& cookies, 286 std::string* auth_code); 287 288 static bool ParseClientLoginToOAuth2Cookie(const std::string& cookie, 289 std::string* auth_code); 290 291 static GoogleServiceAuthError GenerateClientOAuthError( 292 const std::string& data, 293 const net::URLRequestStatus& status); 294 295 // Is this a special case Gaia error for TwoFactor auth? 296 static bool IsSecondFactorSuccess(const std::string& alleged_error); 297 298 // Given parameters, create a ClientLogin request body. 299 static std::string MakeClientLoginBody( 300 const std::string& username, 301 const std::string& password, 302 const std::string& source, 303 const char* const service, 304 const std::string& login_token, 305 const std::string& login_captcha, 306 HostedAccountsSetting allow_hosted_accounts); 307 // Supply the sid / lsid returned from ClientLogin in order to 308 // request a long lived auth token for a service. 309 static std::string MakeIssueAuthTokenBody(const std::string& sid, 310 const std::string& lsid, 311 const char* const service); 312 // Create body to get OAuth2 auth code. 313 static std::string MakeGetAuthCodeBody(); 314 // Given auth code, create body to get OAuth2 token pair. 315 static std::string MakeGetTokenPairBody(const std::string& auth_code); 316 // Supply the lsid returned from ClientLogin in order to fetch 317 // user information. 318 static std::string MakeGetUserInfoBody(const std::string& lsid); 319 320 // Supply the authentication token returned from StartIssueAuthToken. 321 static std::string MakeMergeSessionBody(const std::string& auth_token, 322 const std::string& continue_url, 323 const std::string& source); 324 325 static std::string MakeGetAuthCodeHeader(const std::string& auth_token); 326 327 static std::string MakeClientOAuthBody(const std::string& username, 328 const std::string& password, 329 const std::vector<std::string>& scopes, 330 const std::string& persistent_id, 331 const std::string& friendly_name, 332 const std::string& locale); 333 334 static std::string MakeClientOAuthChallengeResponseBody( 335 const std::string& name, 336 const std::string& token, 337 const std::string& solution); 338 339 static std::string MakeOAuthLoginBody(const std::string& service, 340 const std::string& source); 341 342 void StartOAuth2TokenPairFetch(const std::string& auth_code); 343 344 // Create a fetcher usable for making any Gaia request. |body| is used 345 // as the body of the POST request sent to GAIA. Any strings listed in 346 // |headers| are added as extra HTTP headers in the request. 347 // 348 // |load_flags| are passed to directly to net::URLFetcher::Create() when 349 // creating the URL fetcher. 350 static net::URLFetcher* CreateGaiaFetcher( 351 net::URLRequestContextGetter* getter, 352 const std::string& body, 353 const std::string& headers, 354 const GURL& gaia_gurl, 355 int load_flags, 356 net::URLFetcherDelegate* delegate); 357 358 // From a URLFetcher result, generate an appropriate error. 359 // From the API documentation, both IssueAuthToken and ClientLogin have 360 // the same error returns. 361 static GoogleServiceAuthError GenerateAuthError( 362 const std::string& data, 363 const net::URLRequestStatus& status); 364 365 // These fields are common to GaiaAuthFetcher, same every request 366 GaiaAuthConsumer* const consumer_; 367 net::URLRequestContextGetter* const getter_; 368 std::string source_; 369 const GURL client_login_gurl_; 370 const GURL issue_auth_token_gurl_; 371 const GURL oauth2_token_gurl_; 372 const GURL get_user_info_gurl_; 373 const GURL merge_session_gurl_; 374 const GURL uberauth_token_gurl_; 375 const GURL client_oauth_gurl_; 376 const GURL oauth_login_gurl_; 377 378 // While a fetch is going on: 379 scoped_ptr<net::URLFetcher> fetcher_; 380 GURL client_login_to_oauth2_gurl_; 381 std::string request_body_; 382 std::string requested_service_; // Currently tracked for IssueAuthToken only. 383 bool fetch_pending_; 384 385 friend class GaiaAuthFetcherTest; 386 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CaptchaParse); 387 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDeletedError); 388 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDisabledError); 389 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, BadAuthenticationError); 390 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, IncomprehensibleError); 391 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ServiceUnavailableError); 392 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CheckNormalErrorCode); 393 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CheckTwoFactorResponse); 394 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, LoginNetFailure); 395 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, 396 ParseClientLoginToOAuth2Response); 397 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ParseOAuth2TokenPairResponse); 398 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthSuccess); 399 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthWithQuote); 400 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthChallengeSuccess); 401 FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ClientOAuthChallengeQuote); 402 403 DISALLOW_COPY_AND_ASSIGN(GaiaAuthFetcher); 404}; 405 406#endif // GOOGLE_APIS_GAIA_GAIA_AUTH_FETCHER_H_ 407