Home | History | Annotate | Download | only in login
      1 // Copyright (c) 2011 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 CHROME_BROWSER_CHROMEOS_LOGIN_GOOGLE_AUTHENTICATOR_H_
      6 #define CHROME_BROWSER_CHROMEOS_LOGIN_GOOGLE_AUTHENTICATOR_H_
      7 #pragma once
      8 
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/gtest_prod_util.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "chrome/browser/chromeos/cros/cros_library.h"
     16 #include "chrome/browser/chromeos/cros/cryptohome_library.h"
     17 #include "chrome/browser/chromeos/login/authenticator.h"
     18 #include "chrome/common/net/gaia/gaia_auth_consumer.h"
     19 #include "chrome/common/net/gaia/gaia_auth_fetcher.h"
     20 
     21 // Authenticates a Chromium OS user against the Google Accounts ClientLogin API.
     22 
     23 class Profile;
     24 class GoogleServiceAuthError;
     25 class LoginFailure;
     26 
     27 namespace base {
     28 class Lock;
     29 }
     30 
     31 namespace chromeos {
     32 
     33 class GoogleAuthenticatorTest;
     34 class LoginStatusConsumer;
     35 class UserManager;
     36 
     37 class GoogleAuthenticator : public Authenticator, public GaiaAuthConsumer {
     38  public:
     39   explicit GoogleAuthenticator(LoginStatusConsumer* consumer);
     40   virtual ~GoogleAuthenticator();
     41 
     42   // Given a |username| and |password|, this method attempts to authenticate to
     43   // the Google accounts servers.  The ultimate result is either a callback to
     44   // consumer_->OnLoginSuccess() with the |username| and a vector of
     45   // authentication cookies or a callback to consumer_->OnLoginFailure() with
     46   // an error message.  Uses |profile| when doing URL fetches.
     47   // Optionally could pass CAPTCHA challenge token - |login_token| and
     48   // |login_captcha| string that user has entered.
     49   //
     50   // NOTE: We do not allow HOSTED accounts to log in.  In the event that
     51   // we are asked to authenticate valid HOSTED account creds, we will
     52   // call OnLoginFailure() with HOSTED_NOT_ALLOWED.
     53   //
     54   // Returns true if the attempt gets sent successfully and false if not.
     55   bool AuthenticateToLogin(Profile* profile,
     56                            const std::string& username,
     57                            const std::string& password,
     58                            const std::string& login_token,
     59                            const std::string& login_captcha);
     60 
     61   // Given a |username| and |password|, this method attempts to
     62   // authenticate to the cached credentials. This will never contact
     63   // the server even if it's online. The auth result is sent to
     64   // LoginStatusConsumer in a same way as AuthenticateToLogin does.
     65   bool AuthenticateToUnlock(const std::string& username,
     66                             const std::string& password);
     67 
     68   // Initiates incognito ("browse without signing in") login.
     69   // Mounts tmpfs and notifies consumer on the success/failure.
     70   void LoginOffTheRecord();
     71 
     72   // Public for testing.
     73   void set_system_salt(const chromeos::CryptohomeBlob& new_salt) {
     74     system_salt_ = new_salt;
     75   }
     76   void set_username(const std::string& fake_user) { username_ = fake_user; }
     77   void set_password(const std::string& fake_pass) { password_ = fake_pass; }
     78   void set_password_hash(const std::string& fake_hash) {
     79     ascii_hash_ = fake_hash;
     80   }
     81   void set_user_manager(UserManager* new_manager) {
     82     user_manager_ = new_manager;
     83   }
     84   void SetLocalaccount(const std::string& new_name);
     85 
     86   // These methods must be called on the UI thread, as they make DBus calls
     87   // and also call back to the login UI.
     88   void OnLoginSuccess(const GaiaAuthConsumer::ClientLoginResult& credentials,
     89                       bool request_pending);
     90   void CheckOffline(const LoginFailure& error);
     91   void CheckLocalaccount(const LoginFailure& error);
     92   void OnLoginFailure(const LoginFailure& error);
     93 
     94   // Call these methods on the UI thread.
     95   void RecoverEncryptedData(
     96       const std::string& old_password,
     97       const GaiaAuthConsumer::ClientLoginResult& credentials);
     98   void ResyncEncryptedData(
     99       const GaiaAuthConsumer::ClientLoginResult& credentials);
    100   void RetryAuth(Profile* profile,
    101                  const std::string& username,
    102                  const std::string& password,
    103                  const std::string& login_token,
    104                  const std::string& login_captcha);
    105 
    106   // Callbacks from GaiaAuthFetcher
    107   virtual void OnClientLoginFailure(
    108       const GoogleServiceAuthError& error);
    109   virtual void OnClientLoginSuccess(
    110       const GaiaAuthConsumer::ClientLoginResult& credentials);
    111 
    112  private:
    113 
    114   // If we don't have the system salt yet, loads it from the CryptohomeLibrary.
    115   void LoadSystemSalt();
    116 
    117   // If we haven't already, looks in a file called |filename| next to
    118   // the browser executable for a "localaccount" name, and retrieves it
    119   // if one is present.  If someone attempts to authenticate with this
    120   // username, we will mount a tmpfs for them and let them use the
    121   // browser.
    122   // Should only be called on the FILE thread.
    123   void LoadLocalaccount(const std::string& filename);
    124 
    125   // Stores a hash of |password|, salted with the ascii of |system_salt_|.
    126   std::string HashPassword(const std::string& password);
    127 
    128   // Returns the ascii encoding of the system salt.
    129   std::string SaltAsAscii();
    130 
    131   // Save the current login attempt for use on the next TryClientLogin
    132   // attempt.
    133   void PrepareClientLoginAttempt(const std::string& password,
    134                                  const std::string& login_token,
    135                                  const std::string& login_captcha);
    136   // Clear any cached credentials after we've given up trying to authenticate.
    137   void ClearClientLoginAttempt();
    138 
    139   // Start a client login attempt.  |hosted_policy_| governs whether we are
    140   // willing to authenticate accounts that are HOSTED or not.
    141   // You must set up |gaia_authenticator_| first.
    142   // Reuses existing credentials from the last attempt. You must
    143   // PrepareClientLoginAttempt before calling this.
    144    void TryClientLogin();
    145 
    146   // A callback for use on the UI thread. Cancel the current login
    147   // attempt, and produce a login failure.
    148   void CancelClientLogin();
    149 
    150 
    151   // Converts the binary data |binary| into an ascii hex string and stores
    152   // it in |hex_string|.  Not guaranteed to be NULL-terminated.
    153   // Returns false if |hex_string| is too small, true otherwise.
    154   static bool BinaryToHex(const std::vector<unsigned char>& binary,
    155                           const unsigned int binary_len,
    156                           char* hex_string,
    157                           const unsigned int len);
    158 
    159   void set_hosted_policy(GaiaAuthFetcher::HostedAccountsSetting policy) {
    160     hosted_policy_ = policy;
    161   }
    162 
    163   // The format of said POST body when CAPTCHA token & answer are specified.
    164   static const char kFormatCaptcha[];
    165 
    166   // Magic string indicating that, while a second factor is still
    167   // needed to complete authentication, the user provided the right password.
    168   static const char kSecondFactor[];
    169 
    170   // Name of a file, next to chrome, that contains a local account username.
    171   static const char kLocalaccountFile[];
    172 
    173   // Handles all net communications with Gaia.
    174   scoped_ptr<GaiaAuthFetcher> gaia_authenticator_;
    175 
    176   // Allows us to look up users of the device.
    177   UserManager* user_manager_;
    178 
    179   // Milliseconds until we timeout our attempt to hit ClientLogin.
    180   static const int kClientLoginTimeoutMs;
    181 
    182   // Milliseconds until we re-check whether we've gotten the localaccount name.
    183   static const int kLocalaccountRetryIntervalMs;
    184 
    185   // Whether or not we're accepting HOSTED accounts on this auth attempt.
    186   GaiaAuthFetcher::HostedAccountsSetting hosted_policy_;
    187 
    188   std::string username_;
    189   // These fields are saved so we can retry client login.
    190   std::string password_;
    191   std::string login_token_;
    192   std::string login_captcha_;
    193 
    194   std::string ascii_hash_;
    195   chromeos::CryptohomeBlob system_salt_;
    196   bool unlock_;  // True if authenticating to unlock the computer.
    197   bool try_again_;  // True if we're willing to retry the login attempt.
    198 
    199   std::string localaccount_;
    200   bool checked_for_localaccount_;  // Needed because empty localaccount_ is ok.
    201   base::Lock localaccount_lock_;  // A lock around checked_for_localaccount_.
    202 
    203   friend class GoogleAuthenticatorTest;
    204   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, SaltToAscii);
    205   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, CheckTwoFactorResponse);
    206   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, CheckNormalErrorCode);
    207   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, EmailAddressNoOp);
    208   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, EmailAddressIgnoreCaps);
    209   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest,
    210                            EmailAddressIgnoreDomainCaps);
    211   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest,
    212                            EmailAddressIgnoreOneUsernameDot);
    213   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest,
    214                            EmailAddressIgnoreManyUsernameDots);
    215   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest,
    216                            EmailAddressIgnoreConsecutiveUsernameDots);
    217   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest,
    218                            EmailAddressDifferentOnesRejected);
    219   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest,
    220                            EmailAddressIgnorePlusSuffix);
    221   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest,
    222                            EmailAddressIgnoreMultiPlusSuffix);
    223   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, ReadSaltOnlyOnce);
    224   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, LocalaccountLogin);
    225   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, ReadLocalaccount);
    226   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, ReadLocalaccountTrailingWS);
    227   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, ReadNoLocalaccount);
    228   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, LoginNetFailure);
    229   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, LoginDenied);
    230   FRIEND_TEST_ALL_PREFIXES(GoogleAuthenticatorTest, TwoFactorLogin);
    231 
    232   DISALLOW_COPY_AND_ASSIGN(GoogleAuthenticator);
    233 };
    234 
    235 }  // namespace chromeos
    236 
    237 #endif  // CHROME_BROWSER_CHROMEOS_LOGIN_GOOGLE_AUTHENTICATOR_H_
    238