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. set_system_salt(const chromeos::CryptohomeBlob & new_salt)73 void set_system_salt(const chromeos::CryptohomeBlob& new_salt) { 74 system_salt_ = new_salt; 75 } set_username(const std::string & fake_user)76 void set_username(const std::string& fake_user) { username_ = fake_user; } set_password(const std::string & fake_pass)77 void set_password(const std::string& fake_pass) { password_ = fake_pass; } set_password_hash(const std::string & fake_hash)78 void set_password_hash(const std::string& fake_hash) { 79 ascii_hash_ = fake_hash; 80 } set_user_manager(UserManager * new_manager)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 set_hosted_policy(GaiaAuthFetcher::HostedAccountsSetting policy)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