Home | History | Annotate | Download | only in gaia
      1 // Copyright (c) 2009 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 // Use this class to authenticate users with Gaia and access cookies sent
      6 // by the Gaia servers. This class cannot be used on its own becaue it relies
      7 // on a subclass to provide the virtual Post and GetBackoffDelaySeconds methods.
      8 //
      9 // Sample usage:
     10 // class ActualGaiaAuthenticator : public gaia::GaiaAuthenticator {
     11 //   Provides actual implementation of Post and GetBackoffDelaySeconds.
     12 // };
     13 // ActualGaiaAuthenticator gaia_auth("User-Agent", SERVICE_NAME, kGaiaUrl);
     14 // if (gaia_auth.Authenticate("email", "passwd", SAVE_IN_MEMORY_ONLY,
     15 //                            true)) { // Synchronous
     16 //   // Do something with: gaia_auth.auth_token(), or gaia_auth.sid(),
     17 //   // or gaia_auth.lsid()
     18 // }
     19 //
     20 // Credentials can also be preserved for subsequent requests, though these are
     21 // saved in plain-text in memory, and not very secure on client systems. The
     22 // email address associated with the Gaia account can be read; the password is
     23 // write-only.
     24 
     25 // TODO(sanjeevr): This class has been moved here from the bookmarks sync code.
     26 // While it is a generic class that handles GAIA authentication, there are some
     27 // artifacts of the sync code which needs to be cleaned up.
     28 #ifndef CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_
     29 #define CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_
     30 #pragma once
     31 
     32 #include <string>
     33 
     34 #include "base/basictypes.h"
     35 #include "base/gtest_prod_util.h"
     36 #include "base/message_loop.h"
     37 #include "chrome/common/deprecated/event_sys.h"
     38 #include "googleurl/src/gurl.h"
     39 
     40 namespace gaia {
     41 
     42 static const char kGaiaUrl[] =
     43     "https://www.google.com:443/accounts/ClientLogin";
     44 
     45 // Error codes from Gaia. These will be set correctly for both Gaia V1
     46 // (/ClientAuth) and V2 (/ClientLogin)
     47 enum AuthenticationError {
     48   None                      = 0,
     49   BadAuthentication         = 1,
     50   NotVerified               = 2,
     51   TermsNotAgreed            = 3,
     52   Unknown                   = 4,
     53   AccountDeleted            = 5,
     54   AccountDisabled           = 6,
     55   CaptchaRequired           = 7,
     56   ServiceUnavailable        = 8,
     57   // Errors generated by this class not Gaia.
     58   CredentialsNotSet         = 9,
     59   ConnectionUnavailable     = 10
     60 };
     61 
     62 class GaiaAuthenticator;
     63 
     64 struct GaiaAuthEvent {
     65   enum {
     66     GAIA_AUTH_FAILED,
     67     GAIA_AUTH_SUCCEEDED,
     68     GAIA_AUTHENTICATOR_DESTROYED
     69   }
     70   what_happened;
     71   AuthenticationError error;
     72   const GaiaAuthenticator* authenticator;
     73 
     74   // Lets us use GaiaAuthEvent as its own traits type in hookups.
     75   typedef GaiaAuthEvent EventType;
     76   static inline bool IsChannelShutdownEvent(const GaiaAuthEvent& event) {
     77     return event.what_happened == GAIA_AUTHENTICATOR_DESTROYED;
     78   }
     79 };
     80 
     81 // GaiaAuthenticator can be used to pass user credentials to Gaia and obtain
     82 // cookies set by the Gaia servers.
     83 class GaiaAuthenticator {
     84   FRIEND_TEST_ALL_PREFIXES(GaiaAuthenticatorTest,
     85                            TestNewlineAtEndOfAuthTokenRemoved);
     86  public:
     87 
     88   // Since GaiaAuthenticator can be used for any service, or by any client, you
     89   // must include a user-agent and a service-id when creating one. The
     90   // user_agent is a short string used for simple log analysis. gaia_url is used
     91   // to choose the server to authenticate with (e.g.
     92   // http://www.google.com/accounts/ClientLogin).
     93   GaiaAuthenticator(const std::string& user_agent,
     94                     const std::string& service_id,
     95                     const std::string& gaia_url);
     96 
     97   virtual ~GaiaAuthenticator();
     98 
     99   // This object should only be invoked from the AuthWatcherThread message
    100   // loop, which is injected here.
    101   void set_message_loop(const MessageLoop* loop) {
    102     message_loop_ = loop;
    103   }
    104 
    105   // Pass credentials to authenticate with, or use saved credentials via an
    106   // overload. If authentication succeeds, you can retrieve the authentication
    107   // token via the respective accessors. Returns a boolean indicating whether
    108   // authentication succeeded or not.
    109   bool Authenticate(const std::string& user_name, const std::string& password,
    110                     const std::string& captcha_token,
    111                     const std::string& captcha_value);
    112 
    113   bool Authenticate(const std::string& user_name, const std::string& password);
    114 
    115   // Pass the LSID to authenticate with. If the authentication succeeds, you can
    116   // retrieve the authetication token via the respective accessors. Returns a
    117   // boolean indicating whether authentication succeeded or not.
    118   // Always returns a long lived token.
    119   bool AuthenticateWithLsid(const std::string& lsid);
    120 
    121   // Resets all stored cookies to their default values.
    122   void ResetCredentials();
    123 
    124   void SetUsernamePassword(const std::string& username,
    125                            const std::string& password);
    126 
    127   void SetUsername(const std::string& username);
    128 
    129   // Virtual for testing
    130   virtual void RenewAuthToken(const std::string& auth_token);
    131   void SetAuthToken(const std::string& auth_token);
    132 
    133   struct AuthResults {
    134     AuthResults();
    135     ~AuthResults();
    136 
    137     std::string email;
    138     std::string password;
    139 
    140     // Fields that store various cookies.
    141     std::string sid;
    142     std::string lsid;
    143     std::string auth_token;
    144 
    145     std::string primary_email;
    146 
    147     // Fields for items returned when authentication fails.
    148     std::string error_msg;
    149     enum AuthenticationError auth_error;
    150     std::string auth_error_url;
    151     std::string captcha_token;
    152     std::string captcha_url;
    153   };
    154 
    155  protected:
    156 
    157   struct AuthParams {
    158     AuthParams();
    159     ~AuthParams();
    160 
    161     GaiaAuthenticator* authenticator;
    162     uint32 request_id;
    163     std::string email;
    164     std::string password;
    165     std::string captcha_token;
    166     std::string captcha_value;
    167   };
    168 
    169   // mutex_ must be entered before calling this function.
    170   AuthParams MakeParams(const std::string& user_name,
    171                         const std::string& password,
    172                         const std::string& captcha_token,
    173                         const std::string& captcha_value);
    174 
    175   // The real Authenticate implementations.
    176   bool AuthenticateImpl(const AuthParams& params);
    177   bool AuthenticateImpl(const AuthParams& params, AuthResults* results);
    178 
    179   // virtual for testing purposes.
    180   virtual bool PerformGaiaRequest(const AuthParams& params,
    181                                   AuthResults* results);
    182   virtual bool Post(const GURL& url, const std::string& post_body,
    183                     unsigned long* response_code, std::string* response_body);
    184 
    185   // Caller should fill in results->LSID before calling. Result in
    186   // results->primary_email.
    187   virtual bool LookupEmail(AuthResults* results);
    188 
    189   // Subclasses must override to provide a backoff delay. It is virtual instead
    190   // of pure virtual for testing purposes.
    191   // TODO(sanjeevr): This should be made pure virtual. But this class is
    192   // currently directly being used in sync/engine/authenticator.cc, which is
    193   // wrong.
    194   virtual int GetBackoffDelaySeconds(int current_backoff_delay);
    195 
    196  public:
    197   // Retrieve email.
    198   inline std::string email() const {
    199     DCHECK_EQ(MessageLoop::current(), message_loop_);
    200     return auth_results_.email;
    201   }
    202 
    203   // Retrieve password.
    204   inline std::string password() const {
    205     DCHECK_EQ(MessageLoop::current(), message_loop_);
    206     return auth_results_.password;
    207   }
    208 
    209   // Retrieve AuthToken, if previously authenticated; otherwise returns "".
    210   inline std::string auth_token() const {
    211     DCHECK_EQ(MessageLoop::current(), message_loop_);
    212     return auth_results_.auth_token;
    213   }
    214 
    215   // Retrieve SID cookie. For details, see the Google Accounts documentation.
    216   inline std::string sid() const {
    217     DCHECK_EQ(MessageLoop::current(), message_loop_);
    218     return auth_results_.sid;
    219   }
    220 
    221   // Retrieve LSID cookie. For details, see the Google Accounts documentation.
    222   inline std::string lsid() const {
    223     DCHECK_EQ(MessageLoop::current(), message_loop_);
    224     return auth_results_.lsid;
    225   }
    226 
    227   // Get last authentication error.
    228   inline enum AuthenticationError auth_error() const {
    229     DCHECK_EQ(MessageLoop::current(), message_loop_);
    230     return auth_results_.auth_error;
    231   }
    232 
    233   inline std::string auth_error_url() const {
    234     DCHECK_EQ(MessageLoop::current(), message_loop_);
    235     return auth_results_.auth_error_url;
    236   }
    237 
    238   inline std::string captcha_token() const {
    239     DCHECK_EQ(MessageLoop::current(), message_loop_);
    240     return auth_results_.captcha_token;
    241   }
    242 
    243   inline std::string captcha_url() const {
    244     DCHECK_EQ(MessageLoop::current(), message_loop_);
    245     return auth_results_.captcha_url;
    246   }
    247 
    248   inline AuthResults results() const {
    249     DCHECK_EQ(MessageLoop::current(), message_loop_);
    250     return auth_results_;
    251   }
    252 
    253   typedef EventChannel<GaiaAuthEvent, base::Lock> Channel;
    254 
    255   inline Channel* channel() const {
    256     return channel_;
    257   }
    258 
    259  private:
    260   bool IssueAuthToken(AuthResults* results, const std::string& service_id);
    261 
    262   // Helper method to parse response when authentication succeeds.
    263   void ExtractTokensFrom(const std::string& response, AuthResults* results);
    264   // Helper method to parse response when authentication fails.
    265   void ExtractAuthErrorFrom(const std::string& response, AuthResults* results);
    266 
    267   // Fields for the obvious data items.
    268   const std::string user_agent_;
    269   const std::string service_id_;
    270   const std::string gaia_url_;
    271 
    272   AuthResults auth_results_;
    273 
    274   // When multiple async requests are running, only the one that started most
    275   // recently updates the values.
    276   //
    277   // Note that even though this code was written to handle multiple requests
    278   // simultaneously, the sync code issues auth requests one at a time.
    279   uint32 request_count_;
    280 
    281   Channel* channel_;
    282 
    283   // Used to compute backoff time for next allowed authentication.
    284   int delay_;  // In seconds.
    285   // On Windows, time_t is 64-bit by default. Even though we have defined the
    286   // _USE_32BIT_TIME_T preprocessor flag, other libraries including this header
    287   // may not have that preprocessor flag defined resulting in mismatched class
    288   // sizes. So we explicitly define it as 32-bit on Windows.
    289   // TODO(sanjeevr): Change this to to use base::Time
    290 #if defined(OS_WIN)
    291   __time32_t next_allowed_auth_attempt_time_;
    292 #else  // defined(OS_WIN)
    293   time_t next_allowed_auth_attempt_time_;
    294 #endif  // defined(OS_WIN)
    295   int early_auth_attempt_count_;
    296 
    297   // The message loop all our methods are invoked on.
    298   const MessageLoop* message_loop_;
    299 };
    300 
    301 }  // namespace gaia
    302 #endif  // CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_
    303 
    304