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 28 class GaiaAuthFetcherTest; 29 30 namespace net { 31 class URLFetcher; 32 class URLRequestContextGetter; 33 class URLRequestStatus; 34 } 35 36 class 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