Home | History | Annotate | Download | only in gaia
      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