parallel_authenticator.h revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 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/scoped_ptr.h"
15#include "base/ref_counted.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
26class GaiaAuthFetcher;
27class LoginFailure;
28class Profile;
29
30namespace base {
31class Lock;
32}
33
34namespace chromeos {
35
36class LoginStatusConsumer;
37class ParallelAuthenticator;
38class 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.
55class 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 off the record ("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