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_PARALLEL_AUTHENTICATOR_H_
      6 #define CHROME_BROWSER_CHROMEOS_LOGIN_PARALLEL_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/ref_counted.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "chrome/browser/chromeos/cros/cros_library.h"
     17 #include "chrome/browser/chromeos/cros/cryptohome_library.h"
     18 #include "chrome/browser/chromeos/login/authenticator.h"
     19 #include "chrome/browser/chromeos/login/auth_attempt_state.h"
     20 #include "chrome/browser/chromeos/login/auth_attempt_state_resolver.h"
     21 #include "chrome/browser/chromeos/login/test_attempt_state.h"
     22 #include "chrome/browser/chromeos/login/cryptohome_op.h"
     23 #include "chrome/browser/chromeos/login/online_attempt.h"
     24 #include "chrome/common/net/gaia/gaia_auth_consumer.h"
     25 
     26 class GaiaAuthFetcher;
     27 class LoginFailure;
     28 class Profile;
     29 
     30 namespace base {
     31 class Lock;
     32 }
     33 
     34 namespace chromeos {
     35 
     36 class LoginStatusConsumer;
     37 class ParallelAuthenticator;
     38 class ResolveChecker;
     39 
     40 // Authenticates a Chromium OS user against the Google Accounts ClientLogin API.
     41 //
     42 // Simultaneously attempts authentication both offline and online, failing over
     43 // to the "localaccount" in the event that authentication fails.
     44 //
     45 // At a high, level, here's what happens:
     46 // AuthenticateToLogin() creates an OnlineAttempt and a CryptohomeOp that
     47 // attempt to perform online and offline login simultaneously.  When one of
     48 // these completes, it will store results in a AuthAttemptState owned by
     49 // ParallelAuthenticator and then call Resolve().  Resolve() will attempt to
     50 // determine which AuthState we're in, based on the info at hand.
     51 // It then triggers further action based on the calculated AuthState; this
     52 // further action might include calling back the passed-in LoginStatusConsumer
     53 // to signal that login succeeded or failed, waiting for more outstanding
     54 // operations to complete, or triggering some more CryptohomeOps.
     55 class ParallelAuthenticator : public Authenticator,
     56                               public AuthAttemptStateResolver {
     57  public:
     58   enum AuthState {
     59     CONTINUE,        // State indeterminate; try again when more info available.
     60     NO_MOUNT,        // Cryptohome doesn't exist yet.
     61     FAILED_MOUNT,    // Failed to mount existing cryptohome.
     62     FAILED_REMOVE,   // Failed to remove existing cryptohome.
     63     FAILED_TMPFS,    // Failed to mount tmpfs for guest user
     64     CREATE_NEW,      // Need to create cryptohome for a new user.
     65     RECOVER_MOUNT,   // After RecoverEncryptedData, mount cryptohome.
     66     POSSIBLE_PW_CHANGE,  // Offline login failed, user may have changed pw.
     67     NEED_NEW_PW,     // User changed pw, and we have the old one.
     68     NEED_OLD_PW,     // User changed pw, and we have the new one.
     69     HAVE_NEW_PW,     // We have verified new pw, time to migrate key.
     70     OFFLINE_LOGIN,   // Login succeeded offline.
     71     ONLINE_LOGIN,    // Offline and online login succeeded.
     72     UNLOCK,          // Screen unlock succeeded.
     73     LOCAL_LOGIN,     // Login with localaccount succeded.
     74     ONLINE_FAILED,   // Online login disallowed, but offline succeeded.
     75     LOGIN_FAILED     // Login denied.
     76   };
     77 
     78   explicit ParallelAuthenticator(LoginStatusConsumer* consumer);
     79   virtual ~ParallelAuthenticator();
     80 
     81   // Given a |username| and |password|, this method attempts to authenticate to
     82   // the Google accounts servers and your Chrome OS device simultaneously.
     83   // As soon as we have successfully mounted the encrypted home directory for
     84   // |username|, we will call consumer_->OnLoginSuccess() with |username| and a
     85   // vector of authentication cookies.  If we're still waiting for an online
     86   // result at that time, we'll also pass back a flag indicating that more
     87   // callbacks are on the way; if not, we pass back false.  When the pending
     88   // request completes, either consumer_->OnLoginSuccess() with an indication
     89   // that no more requests are outstanding will be called, or
     90   // consumer_->OnLoginFailure() if appropriate.
     91   //
     92   // Upon failure to login (online fails, then offline fails;
     93   // offline fails, then online fails) consumer_->OnLoginFailure() is called
     94   // with an error message.
     95   //
     96   // In the event that we see an online success and then an offline failure,
     97   // consumer_->OnPasswordChangeDetected() is called.
     98   //
     99   // Uses |profile| when doing URL fetches.
    100   // Optionally could pass CAPTCHA challenge token - |login_token| and
    101   // |login_captcha| string that user has entered.
    102   //
    103   // NOTE: We do not allow HOSTED accounts to log in.  In the event that
    104   // we are asked to authenticate valid HOSTED account creds, we will
    105   // call OnLoginFailure() with HOSTED_NOT_ALLOWED.
    106   //
    107   // Returns true if the attempt gets sent successfully and false if not.
    108   bool AuthenticateToLogin(Profile* profile,
    109                            const std::string& username,
    110                            const std::string& password,
    111                            const std::string& login_token,
    112                            const std::string& login_captcha);
    113 
    114   // Given a |username| and |password|, this method attempts to
    115   // authenticate to the cached credentials. This will never contact
    116   // the server even if it's online. The auth result is sent to
    117   // LoginStatusConsumer in a same way as AuthenticateToLogin does.
    118   bool AuthenticateToUnlock(const std::string& username,
    119                             const std::string& password);
    120 
    121   // Initiates incognito ("browse without signing in") login.
    122   // Mounts tmpfs and notifies consumer on the success/failure.
    123   void LoginOffTheRecord();
    124 
    125   // These methods must be called on the UI thread, as they make DBus calls
    126   // and also call back to the login UI.
    127   void OnLoginSuccess(const GaiaAuthConsumer::ClientLoginResult& credentials,
    128                       bool request_pending);
    129   void OnOffTheRecordLoginSuccess();
    130   void OnPasswordChangeDetected(
    131       const GaiaAuthConsumer::ClientLoginResult& credentials);
    132   void OnLoginFailure(const LoginFailure& error);
    133 
    134   void RecoverEncryptedData(
    135       const std::string& old_password,
    136       const GaiaAuthConsumer::ClientLoginResult& credentials);
    137   void ResyncEncryptedData(
    138       const GaiaAuthConsumer::ClientLoginResult& credentials);
    139   void RetryAuth(Profile* profile,
    140                  const std::string& username,
    141                  const std::string& password,
    142                  const std::string& login_token,
    143                  const std::string& login_captcha);
    144 
    145   // Call this on the FILE thread.
    146   void CheckLocalaccount(const LoginFailure& error);
    147 
    148   // Attempts to make a decision and call back |consumer_| based on
    149   // the state we have gathered at the time of call.  If a decision
    150   // can't be made, defers until the next time this is called.
    151   // When a decision is made, will call back to |consumer_| on the UI thread.
    152   //
    153   // Must be called on the IO thread.
    154   void Resolve();
    155 
    156  private:
    157   // Returns the AuthState we're in, given the status info we have at
    158   // the time of call.
    159   // Must be called on the IO thread.
    160   AuthState ResolveState();
    161 
    162   // Helper for ResolveState().
    163   // Given that we're attempting to auth the user again, with a new password,
    164   // determine which state we're in.  Returns CONTINUE if no resolution.
    165   // Must be called on the IO thread.
    166   AuthState ResolveReauthState();
    167 
    168   // Helper for ResolveState().
    169   // Given that some cryptohome operation has failed, determine which of the
    170   // possible failure states we're in.
    171   // Must be called on the IO thread.
    172   AuthState ResolveCryptohomeFailureState();
    173 
    174   // Helper for ResolveState().
    175   // Given that some cryptohome operation has succeeded, determine which of
    176   // the possible states we're in.
    177   // Must be called on the IO thread.
    178   AuthState ResolveCryptohomeSuccessState();
    179 
    180   // Helper for ResolveState().
    181   // Given that some online auth operation has failed, determine which of the
    182   // possible failure states we're in.  Handles both failure to complete and
    183   // actual failure responses from the server.
    184   // Must be called on the IO thread.
    185   AuthState ResolveOnlineFailureState(AuthState offline_state);
    186 
    187   // Helper for ResolveState().
    188   // Given that some online auth operation has succeeded, determine which of
    189   // the possible success states we're in.
    190   // Must be called on the IO thread.
    191   AuthState ResolveOnlineSuccessState(AuthState offline_state);
    192 
    193   // Used for testing.
    194   void set_attempt_state(TestAttemptState* new_state) {  // takes ownership.
    195     current_state_.reset(new_state);
    196   }
    197 
    198   // Resets |current_state_| and then posts a task to the UI thread to
    199   // Initiate() |to_initiate|.
    200   // Call this method on the IO thread.
    201   void ResyncRecoverHelper(CryptohomeOp* to_initiate);
    202 
    203   // If we don't have the system salt yet, loads it from the CryptohomeLibrary.
    204   void LoadSystemSalt();
    205 
    206   // If we haven't already, looks in a file called |filename| next to
    207   // the browser executable for a "localaccount" name, and retrieves it
    208   // if one is present.  If someone attempts to authenticate with this
    209   // username, we will mount a tmpfs for them and let them use the
    210   // browser.
    211   // Should only be called on the FILE thread.
    212   void LoadLocalaccount(const std::string& filename);
    213 
    214   void SetLocalaccount(const std::string& new_name);
    215 
    216   // Stores a hash of |password|, salted with the ascii of |system_salt_|.
    217   std::string HashPassword(const std::string& password);
    218 
    219   // Returns the ascii encoding of the system salt.
    220   std::string SaltAsAscii();
    221 
    222   // Converts the binary data |binary| into an ascii hex string and stores
    223   // it in |hex_string|.  Not guaranteed to be NULL-terminated.
    224   // Returns false if |hex_string| is too small, true otherwise.
    225   static bool BinaryToHex(const std::vector<unsigned char>& binary,
    226                           const unsigned int binary_len,
    227                           char* hex_string,
    228                           const unsigned int len);
    229 
    230   // Name of a file, next to chrome, that contains a local account username.
    231   static const char kLocalaccountFile[];
    232 
    233   // Milliseconds until we timeout our attempt to hit ClientLogin.
    234   static const int kClientLoginTimeoutMs;
    235 
    236   // Milliseconds until we re-check whether we've gotten the localaccount name.
    237   static const int kLocalaccountRetryIntervalMs;
    238 
    239   // Handles all net communications with Gaia.
    240   scoped_ptr<GaiaAuthFetcher> gaia_authenticator_;
    241 
    242   // Used when we need to try online authentication again, after successful
    243   // mount, but failed online login.
    244   scoped_ptr<AuthAttemptState> reauth_state_;
    245 
    246   scoped_ptr<AuthAttemptState> current_state_;
    247   scoped_refptr<OnlineAttempt> current_online_;
    248   scoped_refptr<CryptohomeOp> mounter_;
    249   scoped_refptr<CryptohomeOp> key_migrator_;
    250   scoped_refptr<CryptohomeOp> data_remover_;
    251   scoped_refptr<CryptohomeOp> guest_mounter_;
    252   scoped_refptr<CryptohomeOp> key_checker_;
    253 
    254   std::string ascii_hash_;
    255   chromeos::CryptohomeBlob system_salt_;
    256 
    257   // When the user has changed her password, but gives us the old one, we will
    258   // be able to mount her cryptohome, but online authentication will fail.
    259   // This allows us to present the same behavior to the caller, regardless
    260   // of the order in which we receive these results.
    261   bool already_reported_success_;
    262   base::Lock success_lock_;  // A lock around already_reported_success_.
    263 
    264   // Status relating to the local "backdoor" account.
    265   std::string localaccount_;
    266   bool checked_for_localaccount_;  // Needed because empty localaccount_ is ok.
    267   base::Lock localaccount_lock_;  // A lock around checked_for_localaccount_.
    268 
    269   friend class ResolveChecker;
    270   friend class ParallelAuthenticatorTest;
    271   FRIEND_TEST_ALL_PREFIXES(ParallelAuthenticatorTest, SaltToAscii);
    272   FRIEND_TEST_ALL_PREFIXES(ParallelAuthenticatorTest, ReadLocalaccount);
    273   FRIEND_TEST_ALL_PREFIXES(ParallelAuthenticatorTest,
    274                            ReadLocalaccountTrailingWS);
    275   FRIEND_TEST_ALL_PREFIXES(ParallelAuthenticatorTest, ReadNoLocalaccount);
    276   DISALLOW_COPY_AND_ASSIGN(ParallelAuthenticator);
    277 };
    278 
    279 }  // namespace chromeos
    280 
    281 #endif  // CHROME_BROWSER_CHROMEOS_LOGIN_PARALLEL_AUTHENTICATOR_H_
    282