1 // Copyright 2014 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/signin/easy_unlock_service.h" 6 7 #include "base/bind.h" 8 #include "base/command_line.h" 9 #include "base/logging.h" 10 #include "base/metrics/field_trial.h" 11 #include "base/prefs/pref_registry_simple.h" 12 #include "base/prefs/pref_service.h" 13 #include "base/prefs/scoped_user_pref_update.h" 14 #include "base/thread_task_runner_handle.h" 15 #include "base/time/time.h" 16 #include "base/values.h" 17 #include "chrome/browser/browser_process.h" 18 #include "chrome/browser/extensions/component_loader.h" 19 #include "chrome/browser/extensions/extension_service.h" 20 #include "chrome/browser/profiles/profile.h" 21 #include "chrome/browser/signin/easy_unlock_auth_attempt.h" 22 #include "chrome/browser/signin/easy_unlock_service_factory.h" 23 #include "chrome/browser/signin/easy_unlock_service_observer.h" 24 #include "chrome/browser/signin/screenlock_bridge.h" 25 #include "chrome/common/chrome_switches.h" 26 #include "chrome/common/extensions/api/easy_unlock_private.h" 27 #include "chrome/common/extensions/extension_constants.h" 28 #include "chrome/common/pref_names.h" 29 #include "components/pref_registry/pref_registry_syncable.h" 30 #include "components/user_manager/user.h" 31 #include "device/bluetooth/bluetooth_adapter.h" 32 #include "device/bluetooth/bluetooth_adapter_factory.h" 33 #include "extensions/browser/event_router.h" 34 #include "extensions/browser/extension_registry.h" 35 #include "extensions/browser/extension_system.h" 36 #include "extensions/common/one_shot_event.h" 37 #include "grit/browser_resources.h" 38 39 #if defined(OS_CHROMEOS) 40 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h" 41 #include "chrome/browser/chromeos/login/session/user_session_manager.h" 42 #include "chrome/browser/chromeos/profiles/profile_helper.h" 43 #include "chromeos/chromeos_switches.h" 44 #include "chromeos/dbus/dbus_thread_manager.h" 45 #include "chromeos/dbus/power_manager_client.h" 46 #endif 47 48 namespace { 49 50 extensions::ComponentLoader* GetComponentLoader( 51 content::BrowserContext* context) { 52 extensions::ExtensionSystem* extension_system = 53 extensions::ExtensionSystem::Get(context); 54 ExtensionService* extension_service = extension_system->extension_service(); 55 return extension_service->component_loader(); 56 } 57 58 PrefService* GetLocalState() { 59 return g_browser_process ? g_browser_process->local_state() : NULL; 60 } 61 62 } // namespace 63 64 // static 65 EasyUnlockService* EasyUnlockService::Get(Profile* profile) { 66 return EasyUnlockServiceFactory::GetForProfile(profile); 67 } 68 69 // static 70 EasyUnlockService* EasyUnlockService::GetForUser( 71 const user_manager::User& user) { 72 #if defined(OS_CHROMEOS) 73 Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(&user); 74 if (!profile) 75 return NULL; 76 return EasyUnlockService::Get(profile); 77 #else 78 return NULL; 79 #endif 80 } 81 82 // static 83 bool EasyUnlockService::IsSignInEnabled() { 84 #if defined(OS_CHROMEOS) 85 const std::string group_name = 86 base::FieldTrialList::FindFullName("EasySignIn"); 87 88 if (CommandLine::ForCurrentProcess()->HasSwitch( 89 chromeos::switches::kDisableEasySignin)) { 90 return false; 91 } 92 93 return group_name == "Enable"; 94 #else 95 return false; 96 #endif 97 } 98 99 class EasyUnlockService::BluetoothDetector 100 : public device::BluetoothAdapter::Observer { 101 public: 102 explicit BluetoothDetector(EasyUnlockService* service) 103 : service_(service), 104 weak_ptr_factory_(this) { 105 } 106 107 virtual ~BluetoothDetector() { 108 if (adapter_.get()) 109 adapter_->RemoveObserver(this); 110 } 111 112 void Initialize() { 113 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) 114 return; 115 116 device::BluetoothAdapterFactory::GetAdapter( 117 base::Bind(&BluetoothDetector::OnAdapterInitialized, 118 weak_ptr_factory_.GetWeakPtr())); 119 } 120 121 bool IsPresent() const { return adapter_.get() && adapter_->IsPresent(); } 122 123 // device::BluetoothAdapter::Observer: 124 virtual void AdapterPresentChanged(device::BluetoothAdapter* adapter, 125 bool present) OVERRIDE { 126 service_->OnBluetoothAdapterPresentChanged(); 127 } 128 129 private: 130 void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter) { 131 adapter_ = adapter; 132 adapter_->AddObserver(this); 133 service_->OnBluetoothAdapterPresentChanged(); 134 } 135 136 // Owner of this class and should out-live this class. 137 EasyUnlockService* service_; 138 scoped_refptr<device::BluetoothAdapter> adapter_; 139 base::WeakPtrFactory<BluetoothDetector> weak_ptr_factory_; 140 141 DISALLOW_COPY_AND_ASSIGN(BluetoothDetector); 142 }; 143 144 #if defined(OS_CHROMEOS) 145 class EasyUnlockService::PowerMonitor 146 : public chromeos::PowerManagerClient::Observer { 147 public: 148 explicit PowerMonitor(EasyUnlockService* service) 149 : service_(service), 150 waking_up_(false), 151 weak_ptr_factory_(this) { 152 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> 153 AddObserver(this); 154 } 155 156 virtual ~PowerMonitor() { 157 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> 158 RemoveObserver(this); 159 } 160 161 bool waking_up() const { return waking_up_; } 162 163 private: 164 // chromeos::PowerManagerClient::Observer: 165 virtual void SuspendImminent() OVERRIDE { 166 service_->PrepareForSuspend(); 167 } 168 169 virtual void SuspendDone(const base::TimeDelta& sleep_duration) OVERRIDE { 170 waking_up_ = true; 171 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 172 FROM_HERE, 173 base::Bind(&PowerMonitor::ResetWakingUp, 174 weak_ptr_factory_.GetWeakPtr()), 175 base::TimeDelta::FromSeconds(5)); 176 service_->UpdateAppState(); 177 // Note that |this| may get deleted after |UpdateAppState| is called. 178 } 179 180 void ResetWakingUp() { 181 waking_up_ = false; 182 service_->UpdateAppState(); 183 } 184 185 EasyUnlockService* service_; 186 bool waking_up_; 187 base::WeakPtrFactory<PowerMonitor> weak_ptr_factory_; 188 189 DISALLOW_COPY_AND_ASSIGN(PowerMonitor); 190 }; 191 #endif 192 193 EasyUnlockService::EasyUnlockService(Profile* profile) 194 : profile_(profile), 195 bluetooth_detector_(new BluetoothDetector(this)), 196 shut_down_(false), 197 weak_ptr_factory_(this) { 198 extensions::ExtensionSystem::Get(profile_)->ready().Post( 199 FROM_HERE, 200 base::Bind(&EasyUnlockService::Initialize, 201 weak_ptr_factory_.GetWeakPtr())); 202 } 203 204 EasyUnlockService::~EasyUnlockService() { 205 } 206 207 // static 208 void EasyUnlockService::RegisterProfilePrefs( 209 user_prefs::PrefRegistrySyncable* registry) { 210 registry->RegisterBooleanPref( 211 prefs::kEasyUnlockEnabled, 212 false, 213 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 214 registry->RegisterDictionaryPref( 215 prefs::kEasyUnlockPairing, 216 new base::DictionaryValue(), 217 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 218 registry->RegisterBooleanPref( 219 prefs::kEasyUnlockAllowed, 220 true, 221 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 222 } 223 224 // static 225 void EasyUnlockService::RegisterPrefs(PrefRegistrySimple* registry) { 226 registry->RegisterDictionaryPref(prefs::kEasyUnlockHardlockState); 227 } 228 229 // static 230 void EasyUnlockService::ResetLocalStateForUser(const std::string& user_id) { 231 DCHECK(!user_id.empty()); 232 233 PrefService* local_state = GetLocalState(); 234 if (!local_state) 235 return; 236 237 DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockHardlockState); 238 update->RemoveWithoutPathExpansion(user_id, NULL); 239 } 240 241 bool EasyUnlockService::IsAllowed() { 242 if (shut_down_) 243 return false; 244 245 if (!IsAllowedInternal()) 246 return false; 247 248 #if defined(OS_CHROMEOS) 249 if (!bluetooth_detector_->IsPresent()) 250 return false; 251 252 return true; 253 #else 254 // TODO(xiyuan): Revisit when non-chromeos platforms are supported. 255 return false; 256 #endif 257 } 258 259 void EasyUnlockService::SetHardlockState( 260 EasyUnlockScreenlockStateHandler::HardlockState state) { 261 const std::string user_id = GetUserEmail(); 262 if (user_id.empty()) 263 return; 264 265 SetHardlockStateForUser(user_id, state); 266 } 267 268 EasyUnlockScreenlockStateHandler::HardlockState 269 EasyUnlockService::GetHardlockState() const { 270 EasyUnlockScreenlockStateHandler::HardlockState state; 271 if (GetPersistedHardlockState(&state)) 272 return state; 273 274 return EasyUnlockScreenlockStateHandler::NO_HARDLOCK; 275 } 276 277 bool EasyUnlockService::GetPersistedHardlockState( 278 EasyUnlockScreenlockStateHandler::HardlockState* state) const { 279 std::string user_id = GetUserEmail(); 280 if (user_id.empty()) 281 return false; 282 283 PrefService* local_state = GetLocalState(); 284 if (!local_state) 285 return false; 286 287 const base::DictionaryValue* dict = 288 local_state->GetDictionary(prefs::kEasyUnlockHardlockState); 289 int state_int; 290 if (dict && dict->GetIntegerWithoutPathExpansion(user_id, &state_int)) { 291 *state = 292 static_cast<EasyUnlockScreenlockStateHandler::HardlockState>(state_int); 293 return true; 294 } 295 296 return false; 297 } 298 299 void EasyUnlockService::ShowInitialUserState() { 300 if (!GetScreenlockStateHandler()) 301 return; 302 303 EasyUnlockScreenlockStateHandler::HardlockState state; 304 bool has_persisted_state = GetPersistedHardlockState(&state); 305 if (!has_persisted_state) 306 return; 307 308 if (state == EasyUnlockScreenlockStateHandler::NO_HARDLOCK) { 309 // Show connecting icon early when there is a persisted non hardlock state. 310 UpdateScreenlockState( 311 EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING); 312 } else { 313 screenlock_state_handler_->MaybeShowHardlockUI(); 314 } 315 } 316 317 EasyUnlockScreenlockStateHandler* 318 EasyUnlockService::GetScreenlockStateHandler() { 319 if (!IsAllowed()) 320 return NULL; 321 if (!screenlock_state_handler_) { 322 screenlock_state_handler_.reset(new EasyUnlockScreenlockStateHandler( 323 GetUserEmail(), 324 GetHardlockState(), 325 ScreenlockBridge::Get())); 326 } 327 return screenlock_state_handler_.get(); 328 } 329 330 bool EasyUnlockService::UpdateScreenlockState( 331 EasyUnlockScreenlockStateHandler::State state) { 332 EasyUnlockScreenlockStateHandler* handler = GetScreenlockStateHandler(); 333 if (!handler) 334 return false; 335 336 handler->ChangeState(state); 337 338 if (state != EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED) 339 auth_attempt_.reset(); 340 return true; 341 } 342 343 void EasyUnlockService::AttemptAuth(const std::string& user_id) { 344 auth_attempt_.reset(new EasyUnlockAuthAttempt( 345 profile_, 346 GetUserEmail(), 347 GetType() == TYPE_REGULAR ? EasyUnlockAuthAttempt::TYPE_UNLOCK 348 : EasyUnlockAuthAttempt::TYPE_SIGNIN)); 349 if (!auth_attempt_->Start(user_id)) 350 auth_attempt_.reset(); 351 } 352 353 void EasyUnlockService::FinalizeUnlock(bool success) { 354 if (auth_attempt_) 355 auth_attempt_->FinalizeUnlock(GetUserEmail(), success); 356 auth_attempt_.reset(); 357 } 358 359 void EasyUnlockService::FinalizeSignin(const std::string& key) { 360 if (!auth_attempt_) 361 return; 362 std::string wrapped_secret = GetWrappedSecret(); 363 if (!wrapped_secret.empty()) 364 auth_attempt_->FinalizeSignin(GetUserEmail(), wrapped_secret, key); 365 auth_attempt_.reset(); 366 } 367 368 void EasyUnlockService::CheckCryptohomeKeysAndMaybeHardlock() { 369 #if defined(OS_CHROMEOS) 370 std::string user_id = GetUserEmail(); 371 if (user_id.empty()) 372 return; 373 374 const base::ListValue* device_list = GetRemoteDevices(); 375 std::set<std::string> paired_devices; 376 if (device_list) { 377 chromeos::EasyUnlockDeviceKeyDataList parsed_paired; 378 chromeos::EasyUnlockKeyManager::RemoteDeviceListToDeviceDataList( 379 *device_list, &parsed_paired); 380 for (const auto& device_key_data : parsed_paired) 381 paired_devices.insert(device_key_data.psk); 382 } 383 if (paired_devices.empty()) { 384 SetHardlockState(EasyUnlockScreenlockStateHandler::NO_PAIRING); 385 return; 386 } 387 388 // No need to compare if a change is already recorded. 389 if (GetHardlockState() == EasyUnlockScreenlockStateHandler::PAIRING_CHANGED || 390 GetHardlockState() == EasyUnlockScreenlockStateHandler::PAIRING_ADDED) { 391 return; 392 } 393 394 chromeos::EasyUnlockKeyManager* key_manager = 395 chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager(); 396 DCHECK(key_manager); 397 398 key_manager->GetDeviceDataList( 399 chromeos::UserContext(user_id), 400 base::Bind(&EasyUnlockService::OnCryptohomeKeysFetchedForChecking, 401 weak_ptr_factory_.GetWeakPtr(), 402 user_id, 403 paired_devices)); 404 #endif 405 } 406 407 void EasyUnlockService::SetTrialRun() { 408 DCHECK(GetType() == TYPE_REGULAR); 409 410 EasyUnlockScreenlockStateHandler* handler = GetScreenlockStateHandler(); 411 if (handler) 412 handler->SetTrialRun(); 413 } 414 415 void EasyUnlockService::AddObserver(EasyUnlockServiceObserver* observer) { 416 observers_.AddObserver(observer); 417 } 418 419 void EasyUnlockService::RemoveObserver(EasyUnlockServiceObserver* observer) { 420 observers_.RemoveObserver(observer); 421 } 422 423 void EasyUnlockService::Shutdown() { 424 if (shut_down_) 425 return; 426 shut_down_ = true; 427 428 ShutdownInternal(); 429 430 weak_ptr_factory_.InvalidateWeakPtrs(); 431 432 ResetScreenlockState(); 433 bluetooth_detector_.reset(); 434 #if defined(OS_CHROMEOS) 435 power_monitor_.reset(); 436 #endif 437 } 438 439 void EasyUnlockService::LoadApp() { 440 DCHECK(IsAllowed()); 441 442 #if defined(GOOGLE_CHROME_BUILD) 443 base::FilePath easy_unlock_path; 444 #if defined(OS_CHROMEOS) 445 easy_unlock_path = base::FilePath("/usr/share/chromeos-assets/easy_unlock"); 446 #endif // defined(OS_CHROMEOS) 447 448 #ifndef NDEBUG 449 // Only allow app path override switch for debug build. 450 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 451 if (command_line->HasSwitch(switches::kEasyUnlockAppPath)) { 452 easy_unlock_path = 453 command_line->GetSwitchValuePath(switches::kEasyUnlockAppPath); 454 } 455 #endif // !defined(NDEBUG) 456 457 if (!easy_unlock_path.empty()) { 458 extensions::ComponentLoader* loader = GetComponentLoader(profile_); 459 if (!loader->Exists(extension_misc::kEasyUnlockAppId)) 460 loader->Add(IDR_EASY_UNLOCK_MANIFEST, easy_unlock_path); 461 462 ExtensionService* extension_service = 463 extensions::ExtensionSystem::Get(profile_)->extension_service(); 464 extension_service->EnableExtension(extension_misc::kEasyUnlockAppId); 465 466 NotifyUserUpdated(); 467 } 468 #endif // defined(GOOGLE_CHROME_BUILD) 469 } 470 471 void EasyUnlockService::DisableAppIfLoaded() { 472 extensions::ComponentLoader* loader = GetComponentLoader(profile_); 473 if (!loader->Exists(extension_misc::kEasyUnlockAppId)) 474 return; 475 476 ExtensionService* extension_service = 477 extensions::ExtensionSystem::Get(profile_)->extension_service(); 478 extension_service->DisableExtension(extension_misc::kEasyUnlockAppId, 479 extensions::Extension::DISABLE_RELOAD); 480 } 481 482 void EasyUnlockService::UnloadApp() { 483 GetComponentLoader(profile_)->Remove(extension_misc::kEasyUnlockAppId); 484 } 485 486 void EasyUnlockService::ReloadApp() { 487 // Make sure lock screen state set by the extension gets reset. 488 ResetScreenlockState(); 489 490 if (!GetComponentLoader(profile_)->Exists(extension_misc::kEasyUnlockAppId)) 491 return; 492 extensions::ExtensionSystem* extension_system = 493 extensions::ExtensionSystem::Get(profile_); 494 extension_system->extension_service()->ReloadExtension( 495 extension_misc::kEasyUnlockAppId); 496 NotifyUserUpdated(); 497 } 498 499 void EasyUnlockService::UpdateAppState() { 500 if (IsAllowed()) { 501 LoadApp(); 502 503 #if defined(OS_CHROMEOS) 504 if (!power_monitor_) 505 power_monitor_.reset(new PowerMonitor(this)); 506 #endif 507 } else { 508 bool bluetooth_waking_up = false; 509 #if defined(OS_CHROMEOS) 510 // If the service is not allowed due to bluetooth not being detected just 511 // after system suspend is done, give bluetooth more time to be detected 512 // before disabling the app (and resetting screenlock state). 513 bluetooth_waking_up = 514 power_monitor_.get() && power_monitor_->waking_up() && 515 !bluetooth_detector_->IsPresent(); 516 #endif 517 518 if (!bluetooth_waking_up) { 519 DisableAppIfLoaded(); 520 ResetScreenlockState(); 521 #if defined(OS_CHROMEOS) 522 power_monitor_.reset(); 523 #endif 524 } 525 } 526 } 527 528 void EasyUnlockService::NotifyUserUpdated() { 529 std::string user_id = GetUserEmail(); 530 if (user_id.empty()) 531 return; 532 533 // Notify the easy unlock app that the user info changed. 534 extensions::api::easy_unlock_private::UserInfo info; 535 info.user_id = user_id; 536 info.logged_in = GetType() == TYPE_REGULAR; 537 info.data_ready = info.logged_in || GetRemoteDevices() != NULL; 538 539 scoped_ptr<base::ListValue> args(new base::ListValue()); 540 args->Append(info.ToValue().release()); 541 542 scoped_ptr<extensions::Event> event(new extensions::Event( 543 extensions::api::easy_unlock_private::OnUserInfoUpdated::kEventName, 544 args.Pass())); 545 546 extensions::EventRouter::Get(profile_)->DispatchEventToExtension( 547 extension_misc::kEasyUnlockAppId, event.Pass()); 548 } 549 550 void EasyUnlockService::NotifyTurnOffOperationStatusChanged() { 551 FOR_EACH_OBSERVER( 552 EasyUnlockServiceObserver, observers_, OnTurnOffOperationStatusChanged()); 553 } 554 555 void EasyUnlockService::ResetScreenlockState() { 556 screenlock_state_handler_.reset(); 557 auth_attempt_.reset(); 558 } 559 560 void EasyUnlockService::SetScreenlockHardlockedState( 561 EasyUnlockScreenlockStateHandler::HardlockState state) { 562 if (screenlock_state_handler_) 563 screenlock_state_handler_->SetHardlockState(state); 564 if (state != EasyUnlockScreenlockStateHandler::NO_HARDLOCK) 565 auth_attempt_.reset(); 566 } 567 568 void EasyUnlockService::Initialize() { 569 InitializeInternal(); 570 571 #if defined(OS_CHROMEOS) 572 // Only start Bluetooth detection for ChromeOS since the feature is 573 // only offered on ChromeOS. Enabling this on non-ChromeOS platforms 574 // previously introduced a performance regression: http://crbug.com/404482 575 // Make sure not to reintroduce a performance regression if re-enabling on 576 // additional platforms. 577 // TODO(xiyuan): Revisit when non-chromeos platforms are supported. 578 bluetooth_detector_->Initialize(); 579 #endif // defined(OS_CHROMEOS) 580 } 581 582 void EasyUnlockService::OnBluetoothAdapterPresentChanged() { 583 UpdateAppState(); 584 } 585 586 void EasyUnlockService::SetHardlockStateForUser( 587 const std::string& user_id, 588 EasyUnlockScreenlockStateHandler::HardlockState state) { 589 DCHECK(!user_id.empty()); 590 591 PrefService* local_state = GetLocalState(); 592 if (!local_state) 593 return; 594 595 DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockHardlockState); 596 update->SetIntegerWithoutPathExpansion(user_id, static_cast<int>(state)); 597 598 if (GetUserEmail() == user_id) 599 SetScreenlockHardlockedState(state); 600 } 601 602 #if defined(OS_CHROMEOS) 603 void EasyUnlockService::OnCryptohomeKeysFetchedForChecking( 604 const std::string& user_id, 605 const std::set<std::string> paired_devices, 606 bool success, 607 const chromeos::EasyUnlockDeviceKeyDataList& key_data_list) { 608 DCHECK(!user_id.empty() && !paired_devices.empty()); 609 610 if (!success) { 611 SetHardlockStateForUser(user_id, 612 EasyUnlockScreenlockStateHandler::NO_PAIRING); 613 return; 614 } 615 616 std::set<std::string> devices_in_cryptohome; 617 for (const auto& device_key_data : key_data_list) 618 devices_in_cryptohome.insert(device_key_data.psk); 619 620 if (paired_devices != devices_in_cryptohome || 621 GetHardlockState() == EasyUnlockScreenlockStateHandler::NO_PAIRING) { 622 SetHardlockStateForUser( 623 user_id, 624 devices_in_cryptohome.empty() 625 ? EasyUnlockScreenlockStateHandler::PAIRING_ADDED 626 : EasyUnlockScreenlockStateHandler::PAIRING_CHANGED); 627 } 628 } 629 #endif 630 631 void EasyUnlockService::PrepareForSuspend() { 632 DisableAppIfLoaded(); 633 if (screenlock_state_handler_ && screenlock_state_handler_->IsActive()) { 634 UpdateScreenlockState( 635 EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING); 636 } 637 } 638 639