1 // Copyright (c) 2012 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 #include "chrome/browser/chromeos/login/managed/managed_user_authenticator.h" 6 7 #include "base/bind.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_util.h" 10 #include "chrome/browser/chromeos/boot_times_loader.h" 11 #include "chrome/browser/chromeos/login/auth/key.h" 12 #include "chromeos/cryptohome/async_method_caller.h" 13 #include "chromeos/cryptohome/cryptohome_parameters.h" 14 #include "chromeos/cryptohome/system_salt_getter.h" 15 #include "chromeos/dbus/cryptohome_client.h" 16 #include "chromeos/dbus/dbus_thread_manager.h" 17 #include "content/public/browser/browser_thread.h" 18 #include "crypto/sha2.h" 19 #include "google_apis/gaia/gaia_auth_util.h" 20 #include "third_party/cros_system_api/dbus/service_constants.h" 21 22 using content::BrowserThread; 23 24 namespace chromeos { 25 26 namespace { 27 28 // Records status and calls resolver->Resolve(). 29 void TriggerResolve(ManagedUserAuthenticator::AuthAttempt* attempt, 30 scoped_refptr<ManagedUserAuthenticator> resolver, 31 bool success, 32 cryptohome::MountError return_code) { 33 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 34 attempt->RecordCryptohomeStatus(success, return_code); 35 resolver->Resolve(); 36 } 37 38 // Records status and calls resolver->Resolve(). 39 void TriggerResolveResult(ManagedUserAuthenticator::AuthAttempt* attempt, 40 scoped_refptr<ManagedUserAuthenticator> resolver, 41 bool success, 42 const std::string& result) { 43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 44 attempt->RecordHash(result); 45 resolver->Resolve(); 46 } 47 48 // Calls TriggerResolve while adding login time marker. 49 void TriggerResolveWithLoginTimeMarker( 50 const std::string& marker_name, 51 ManagedUserAuthenticator::AuthAttempt* attempt, 52 scoped_refptr<ManagedUserAuthenticator> resolver, 53 bool success, 54 cryptohome::MountError return_code) { 55 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(marker_name, false); 56 TriggerResolve(attempt, resolver, success, return_code); 57 } 58 59 // Calls cryptohome's mount method. 60 void Mount(ManagedUserAuthenticator::AuthAttempt* attempt, 61 scoped_refptr<ManagedUserAuthenticator> resolver, 62 int flags, 63 const std::string& system_salt) { 64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 65 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 66 "CryptohomeMount-LMU-Start", false); 67 68 Key key(attempt->password); 69 key.Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, system_salt); 70 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMount( 71 attempt->username, 72 key.GetSecret(), 73 flags, 74 base::Bind(&TriggerResolveWithLoginTimeMarker, 75 "CryptohomeMount-LMU-End", 76 attempt, 77 resolver)); 78 79 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername( 80 attempt->username, 81 base::Bind(&TriggerResolveResult, attempt, resolver)); 82 } 83 84 // Calls cryptohome's addKey method. 85 void AddKey(ManagedUserAuthenticator::AuthAttempt* attempt, 86 scoped_refptr<ManagedUserAuthenticator> resolver, 87 const std::string& plain_text_master_key, 88 const std::string& system_salt) { 89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 90 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker( 91 "CryptohomeAddKey-LMU-Start", false); 92 93 Key user_key(attempt->password); 94 user_key.Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, system_salt); 95 Key master_key(plain_text_master_key); 96 master_key.Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, system_salt); 97 cryptohome::AsyncMethodCaller::GetInstance()->AsyncAddKey( 98 attempt->username, 99 user_key.GetSecret(), 100 master_key.GetSecret(), 101 base::Bind(&TriggerResolveWithLoginTimeMarker, 102 "CryptohomeAddKey-LMU-End", 103 attempt, 104 resolver)); 105 } 106 107 } // namespace 108 109 ManagedUserAuthenticator::ManagedUserAuthenticator(AuthStatusConsumer* consumer) 110 : consumer_(consumer) {} 111 112 void ManagedUserAuthenticator::AuthenticateToMount( 113 const std::string& username, 114 const std::string& password) { 115 std::string canonicalized = gaia::CanonicalizeEmail(username); 116 117 current_state_.reset(new ManagedUserAuthenticator::AuthAttempt( 118 canonicalized, password, false)); 119 120 SystemSaltGetter::Get()->GetSystemSalt( 121 base::Bind(&Mount, 122 current_state_.get(), 123 scoped_refptr<ManagedUserAuthenticator>(this), 124 cryptohome::MOUNT_FLAGS_NONE)); 125 } 126 127 void ManagedUserAuthenticator::AuthenticateToCreate( 128 const std::string& username, 129 const std::string& password) { 130 std::string canonicalized = gaia::CanonicalizeEmail(username); 131 132 current_state_.reset(new ManagedUserAuthenticator::AuthAttempt( 133 canonicalized, password, false)); 134 135 SystemSaltGetter::Get()->GetSystemSalt( 136 base::Bind(&Mount, 137 current_state_.get(), 138 scoped_refptr<ManagedUserAuthenticator>(this), 139 cryptohome::CREATE_IF_MISSING)); 140 } 141 142 void ManagedUserAuthenticator::AddMasterKey( 143 const std::string& username, 144 const std::string& password, 145 const std::string& master_key) { 146 std::string canonicalized = gaia::CanonicalizeEmail(username); 147 148 current_state_.reset(new ManagedUserAuthenticator::AuthAttempt( 149 canonicalized, password, true)); 150 151 SystemSaltGetter::Get()->GetSystemSalt( 152 base::Bind(&AddKey, 153 current_state_.get(), 154 scoped_refptr<ManagedUserAuthenticator>(this), 155 master_key)); 156 } 157 158 void ManagedUserAuthenticator::OnAuthenticationSuccess( 159 const std::string& mount_hash, 160 bool add_key) { 161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 162 VLOG(1) << "Locally managed user authentication success"; 163 if (consumer_) { 164 if (add_key) 165 consumer_->OnAddKeySuccess(); 166 else 167 consumer_->OnMountSuccess(mount_hash); 168 } 169 } 170 171 void ManagedUserAuthenticator::OnAuthenticationFailure( 172 ManagedUserAuthenticator::AuthState state) { 173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 174 LOG(WARNING) << "Locally managed user authentication failure"; 175 if (consumer_) 176 consumer_->OnAuthenticationFailure(state); 177 } 178 179 void ManagedUserAuthenticator::Resolve() { 180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 181 ManagedUserAuthenticator::AuthState state = ResolveState(); 182 VLOG(1) << "Resolved state to: " << state; 183 switch (state) { 184 case CONTINUE: 185 // These are intermediate states; we need more info from a request that 186 // is still pending. 187 break; 188 case FAILED_MOUNT: 189 // In this case, whether login succeeded or not, we can't log 190 // the user in because their data is horked. So, override with 191 // the appropriate failure. 192 BrowserThread::PostTask( 193 BrowserThread::UI, 194 FROM_HERE, 195 base::Bind( 196 &ManagedUserAuthenticator::OnAuthenticationFailure, this, state)); 197 break; 198 case NO_MOUNT: 199 // In this case, whether login succeeded or not, we can't log 200 // the user in because no data exist. So, override with 201 // the appropriate failure. 202 BrowserThread::PostTask( 203 BrowserThread::UI, 204 FROM_HERE, 205 base::Bind( 206 &ManagedUserAuthenticator::OnAuthenticationFailure, this, state)); 207 break; 208 case FAILED_TPM: 209 // In this case, we tried to create/mount cryptohome and failed 210 // because of the critical TPM error. 211 // Chrome will notify user and request reboot. 212 BrowserThread::PostTask( 213 BrowserThread::UI, 214 FROM_HERE, 215 base::Bind( 216 &ManagedUserAuthenticator::OnAuthenticationFailure, this, state)); 217 break; 218 case SUCCESS: 219 VLOG(2) << "Locally managed user login"; 220 BrowserThread::PostTask( 221 BrowserThread::UI, 222 FROM_HERE, 223 base::Bind(&ManagedUserAuthenticator::OnAuthenticationSuccess, 224 this, 225 current_state_->hash(), 226 current_state_->add_key)); 227 break; 228 default: 229 NOTREACHED(); 230 break; 231 } 232 } 233 234 ManagedUserAuthenticator::~ManagedUserAuthenticator() {} 235 236 ManagedUserAuthenticator::AuthState ManagedUserAuthenticator::ResolveState() { 237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 238 // If we haven't mounted the user's home dir yet, we can't be done. 239 // We never get past here if a cryptohome op is still pending. 240 // This is an important invariant. 241 if (!current_state_->cryptohome_complete()) 242 return CONTINUE; 243 if (!current_state_->add_key && !current_state_->hash_obtained()) 244 return CONTINUE; 245 246 AuthState state; 247 248 if (current_state_->cryptohome_outcome()) 249 state = ResolveCryptohomeSuccessState(); 250 else 251 state = ResolveCryptohomeFailureState(); 252 253 DCHECK(current_state_->cryptohome_complete()); 254 DCHECK(current_state_->hash_obtained() || current_state_->add_key); 255 return state; 256 } 257 258 ManagedUserAuthenticator::AuthState 259 ManagedUserAuthenticator::ResolveCryptohomeFailureState() { 260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 261 if (current_state_->cryptohome_code() == 262 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) { 263 // Critical TPM error detected, reboot needed. 264 return FAILED_TPM; 265 } 266 267 if (current_state_->cryptohome_code() == 268 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) { 269 // If we tried a mount but the user did not exist, then we should wait 270 // for online login to succeed and try again with the "create" flag set. 271 return NO_MOUNT; 272 } 273 274 return FAILED_MOUNT; 275 } 276 277 ManagedUserAuthenticator::AuthState 278 ManagedUserAuthenticator::ResolveCryptohomeSuccessState() { 279 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 280 return SUCCESS; 281 } 282 283 ManagedUserAuthenticator::AuthAttempt::AuthAttempt(const std::string& username, 284 const std::string& password, 285 bool add_key_attempt) 286 : username(username), 287 password(password), 288 add_key(add_key_attempt), 289 cryptohome_complete_(false), 290 cryptohome_outcome_(false), 291 hash_obtained_(false), 292 cryptohome_code_(cryptohome::MOUNT_ERROR_NONE) {} 293 294 ManagedUserAuthenticator::AuthAttempt::~AuthAttempt() {} 295 296 void ManagedUserAuthenticator::AuthAttempt::RecordCryptohomeStatus( 297 bool cryptohome_outcome, 298 cryptohome::MountError cryptohome_code) { 299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 300 cryptohome_complete_ = true; 301 cryptohome_outcome_ = cryptohome_outcome; 302 cryptohome_code_ = cryptohome_code; 303 } 304 305 void ManagedUserAuthenticator::AuthAttempt::RecordHash( 306 const std::string& hash) { 307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 308 hash_obtained_ = true; 309 hash_ = hash; 310 } 311 312 bool ManagedUserAuthenticator::AuthAttempt::cryptohome_complete() { 313 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 314 return cryptohome_complete_; 315 } 316 317 bool ManagedUserAuthenticator::AuthAttempt::cryptohome_outcome() { 318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 319 return cryptohome_outcome_; 320 } 321 322 cryptohome::MountError 323 ManagedUserAuthenticator::AuthAttempt::cryptohome_code() { 324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 325 return cryptohome_code_; 326 } 327 328 bool ManagedUserAuthenticator::AuthAttempt::hash_obtained() { 329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 330 return hash_obtained_; 331 } 332 333 std::string ManagedUserAuthenticator::AuthAttempt::hash() { 334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 335 return hash_; 336 } 337 338 } // namespace chromeos 339