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
23class Profile;
24class GoogleServiceAuthError;
25class LoginFailure;
26
27namespace base {
28class Lock;
29}
30
31namespace chromeos {
32
33class GoogleAuthenticatorTest;
34class LoginStatusConsumer;
35class UserManager;
36
37class 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