| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/command_line.h" |
| #include "base/guid.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/system/sys_info.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "base/version.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chromeos/login/easy_unlock/chrome_proximity_auth_client.h" |
| #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h" |
| #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_factory.h" |
| #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h" |
| #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h" |
| #include "chrome/browser/chromeos/login/session/user_session_manager.h" |
| #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/extensions/extension_constants.h" |
| #include "chrome/common/pref_names.h" |
| #include "chromeos/components/multidevice/logging/logging.h" |
| #include "chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.h" |
| #include "chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.h" |
| #include "chromeos/components/proximity_auth/proximity_auth_system.h" |
| #include "chromeos/components/proximity_auth/screenlock_bridge.h" |
| #include "chromeos/components/proximity_auth/switches.h" |
| #include "chromeos/dbus/dbus_thread_manager.h" |
| #include "chromeos/dbus/power_manager_client.h" |
| #include "chromeos/login/auth/user_context.h" |
| #include "components/account_id/account_id.h" |
| #include "components/pref_registry/pref_registry_syncable.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/prefs/scoped_user_pref_update.h" |
| #include "components/session_manager/core/session_manager.h" |
| #include "components/user_manager/user.h" |
| #include "components/version_info/version_info.h" |
| #include "device/bluetooth/bluetooth_adapter.h" |
| #include "device/bluetooth/bluetooth_adapter_factory.h" |
| |
| using proximity_auth::ScreenlockState; |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| PrefService* GetLocalState() { |
| return g_browser_process ? g_browser_process->local_state() : NULL; |
| } |
| |
| void RecordAuthResultFailure( |
| EasyUnlockAuthAttempt::Type auth_attempt_type, |
| SmartLockMetricsRecorder::SmartLockAuthResultFailureReason failure_reason) { |
| if (auth_attempt_type == EasyUnlockAuthAttempt::TYPE_UNLOCK) |
| SmartLockMetricsRecorder::RecordAuthResultUnlockFailure(failure_reason); |
| else if (auth_attempt_type == EasyUnlockAuthAttempt::TYPE_SIGNIN) |
| SmartLockMetricsRecorder::RecordAuthResultSignInFailure(failure_reason); |
| } |
| |
| } // namespace |
| |
| // static |
| EasyUnlockService* EasyUnlockService::Get(Profile* profile) { |
| return EasyUnlockServiceFactory::GetForBrowserContext(profile); |
| } |
| |
| // static |
| EasyUnlockService* EasyUnlockService::GetForUser( |
| const user_manager::User& user) { |
| Profile* profile = ProfileHelper::Get()->GetProfileByUser(&user); |
| if (!profile) |
| return NULL; |
| return EasyUnlockService::Get(profile); |
| } |
| |
| class EasyUnlockService::BluetoothDetector |
| : public device::BluetoothAdapter::Observer { |
| public: |
| explicit BluetoothDetector(EasyUnlockService* service) |
| : service_(service), weak_ptr_factory_(this) {} |
| |
| ~BluetoothDetector() override { |
| if (adapter_.get()) |
| adapter_->RemoveObserver(this); |
| } |
| |
| void Initialize() { |
| if (!device::BluetoothAdapterFactory::IsBluetoothSupported()) |
| return; |
| |
| device::BluetoothAdapterFactory::GetAdapter( |
| base::BindOnce(&BluetoothDetector::OnAdapterInitialized, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| bool IsPresent() const { return adapter_.get() && adapter_->IsPresent(); } |
| |
| // device::BluetoothAdapter::Observer: |
| void AdapterPresentChanged(device::BluetoothAdapter* adapter, |
| bool present) override { |
| service_->OnBluetoothAdapterPresentChanged(); |
| } |
| |
| private: |
| void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter) { |
| adapter_ = adapter; |
| adapter_->AddObserver(this); |
| service_->OnBluetoothAdapterPresentChanged(); |
| |
| // TODO(tengs): At the moment, there is no way for Bluetooth discoverability |
| // to be turned on except through the Easy Unlock setup. If we step on any |
| // toes in the future then we need to revisit this guard. |
| if (adapter_->IsDiscoverable()) |
| TurnOffBluetoothDiscoverability(); |
| } |
| |
| void TurnOffBluetoothDiscoverability() { |
| if (adapter_) { |
| adapter_->SetDiscoverable(false, base::DoNothing(), base::DoNothing()); |
| } |
| } |
| |
| // Owner of this class and should out-live this class. |
| EasyUnlockService* service_; |
| scoped_refptr<device::BluetoothAdapter> adapter_; |
| base::WeakPtrFactory<BluetoothDetector> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BluetoothDetector); |
| }; |
| |
| class EasyUnlockService::PowerMonitor : public PowerManagerClient::Observer { |
| public: |
| explicit PowerMonitor(EasyUnlockService* service) |
| : service_(service), waking_up_(false), weak_ptr_factory_(this) { |
| DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this); |
| } |
| |
| ~PowerMonitor() override { |
| DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this); |
| } |
| |
| // Called when the remote device has been authenticated to record the time |
| // delta from waking up. No time will be recorded if the start-up time has |
| // already been recorded or if the system never went to sleep previously. |
| void RecordStartUpTime() { |
| if (wake_up_time_.is_null()) |
| return; |
| UMA_HISTOGRAM_MEDIUM_TIMES("EasyUnlock.StartupTimeFromSuspend", |
| base::Time::Now() - wake_up_time_); |
| wake_up_time_ = base::Time(); |
| } |
| |
| bool waking_up() const { return waking_up_; } |
| |
| private: |
| // PowerManagerClient::Observer: |
| void SuspendImminent(power_manager::SuspendImminent::Reason reason) override { |
| service_->PrepareForSuspend(); |
| } |
| |
| void SuspendDone(const base::TimeDelta& sleep_duration) override { |
| waking_up_ = true; |
| wake_up_time_ = base::Time::Now(); |
| base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| FROM_HERE, |
| base::BindOnce(&PowerMonitor::ResetWakingUp, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::TimeDelta::FromSeconds(5)); |
| service_->OnSuspendDone(); |
| service_->UpdateAppState(); |
| // Note that |this| may get deleted after |UpdateAppState| is called. |
| } |
| |
| void ResetWakingUp() { |
| waking_up_ = false; |
| service_->UpdateAppState(); |
| } |
| |
| EasyUnlockService* service_; |
| bool waking_up_; |
| base::Time wake_up_time_; |
| base::WeakPtrFactory<PowerMonitor> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PowerMonitor); |
| }; |
| |
| EasyUnlockService::EasyUnlockService( |
| Profile* profile, |
| secure_channel::SecureChannelClient* secure_channel_client) |
| : profile_(profile), |
| secure_channel_client_(secure_channel_client), |
| proximity_auth_client_(profile), |
| bluetooth_detector_(new BluetoothDetector(this)), |
| shut_down_(false), |
| tpm_key_checked_(false), |
| weak_ptr_factory_(this) {} |
| |
| EasyUnlockService::~EasyUnlockService() {} |
| |
| // static |
| void EasyUnlockService::RegisterProfilePrefs( |
| user_prefs::PrefRegistrySyncable* registry) { |
| registry->RegisterDictionaryPref(prefs::kEasyUnlockPairing); |
| proximity_auth::ProximityAuthProfilePrefManager::RegisterPrefs(registry); |
| } |
| |
| // static |
| void EasyUnlockService::RegisterPrefs(PrefRegistrySimple* registry) { |
| registry->RegisterDictionaryPref(prefs::kEasyUnlockHardlockState); |
| EasyUnlockTpmKeyManager::RegisterLocalStatePrefs(registry); |
| proximity_auth::ProximityAuthLocalStatePrefManager::RegisterPrefs(registry); |
| } |
| |
| // static |
| void EasyUnlockService::ResetLocalStateForUser(const AccountId& account_id) { |
| DCHECK(account_id.is_valid()); |
| |
| PrefService* local_state = GetLocalState(); |
| if (!local_state) |
| return; |
| |
| DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockHardlockState); |
| update->RemoveWithoutPathExpansion(account_id.GetUserEmail(), NULL); |
| |
| EasyUnlockTpmKeyManager::ResetLocalStateForUser(account_id); |
| } |
| |
| void EasyUnlockService::Initialize() { |
| InitializeInternal(); |
| |
| bluetooth_detector_->Initialize(); |
| } |
| |
| proximity_auth::ProximityAuthPrefManager* |
| EasyUnlockService::GetProximityAuthPrefManager() { |
| NOTREACHED(); |
| return nullptr; |
| } |
| |
| bool EasyUnlockService::IsAllowed() const { |
| if (shut_down_) |
| return false; |
| |
| if (!IsAllowedInternal()) |
| return false; |
| |
| if (!bluetooth_detector_->IsPresent()) |
| return false; |
| |
| return true; |
| } |
| |
| bool EasyUnlockService::IsEnabled() const { |
| return false; |
| } |
| |
| bool EasyUnlockService::IsChromeOSLoginEnabled() const { |
| return false; |
| } |
| |
| void EasyUnlockService::SetHardlockState( |
| EasyUnlockScreenlockStateHandler::HardlockState state) { |
| const AccountId& account_id = GetAccountId(); |
| if (!account_id.is_valid()) |
| return; |
| |
| if (state == GetHardlockState()) |
| return; |
| |
| SetHardlockStateForUser(account_id, state); |
| } |
| |
| EasyUnlockScreenlockStateHandler::HardlockState |
| EasyUnlockService::GetHardlockState() const { |
| EasyUnlockScreenlockStateHandler::HardlockState state; |
| if (GetPersistedHardlockState(&state)) |
| return state; |
| |
| return EasyUnlockScreenlockStateHandler::NO_HARDLOCK; |
| } |
| |
| bool EasyUnlockService::GetPersistedHardlockState( |
| EasyUnlockScreenlockStateHandler::HardlockState* state) const { |
| const AccountId& account_id = GetAccountId(); |
| if (!account_id.is_valid()) |
| return false; |
| |
| PrefService* local_state = GetLocalState(); |
| if (!local_state) |
| return false; |
| |
| const base::DictionaryValue* dict = |
| local_state->GetDictionary(prefs::kEasyUnlockHardlockState); |
| int state_int; |
| if (dict && dict->GetIntegerWithoutPathExpansion(account_id.GetUserEmail(), |
| &state_int)) { |
| *state = |
| static_cast<EasyUnlockScreenlockStateHandler::HardlockState>(state_int); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| EasyUnlockScreenlockStateHandler* |
| EasyUnlockService::GetScreenlockStateHandler() { |
| if (!IsAllowed()) |
| return NULL; |
| if (!screenlock_state_handler_) { |
| screenlock_state_handler_.reset(new EasyUnlockScreenlockStateHandler( |
| GetAccountId(), GetHardlockState(), |
| proximity_auth::ScreenlockBridge::Get())); |
| } |
| return screenlock_state_handler_.get(); |
| } |
| |
| bool EasyUnlockService::UpdateScreenlockState(ScreenlockState state) { |
| EasyUnlockScreenlockStateHandler* handler = GetScreenlockStateHandler(); |
| if (!handler) |
| return false; |
| |
| handler->ChangeState(state); |
| |
| if (state == ScreenlockState::AUTHENTICATED) { |
| if (power_monitor_) |
| power_monitor_->RecordStartUpTime(); |
| } else if (auth_attempt_) { |
| // Clean up existing auth attempt if we can no longer authenticate the |
| // remote device. |
| auth_attempt_.reset(); |
| |
| if (!handler->InStateValidOnRemoteAuthFailure()) |
| HandleAuthFailure(GetAccountId()); |
| } |
| |
| return true; |
| } |
| |
| void EasyUnlockService::OnUserEnteredPassword() { |
| if (proximity_auth_system_) |
| proximity_auth_system_->CancelConnectionAttempt(); |
| } |
| |
| void EasyUnlockService::AttemptAuth(const AccountId& account_id) { |
| const EasyUnlockAuthAttempt::Type auth_attempt_type = |
| GetType() == TYPE_REGULAR ? EasyUnlockAuthAttempt::TYPE_UNLOCK |
| : EasyUnlockAuthAttempt::TYPE_SIGNIN; |
| if (auth_attempt_) { |
| PA_LOG(VERBOSE) << "Already attempting auth, skipping this request."; |
| return; |
| } |
| |
| if (!GetAccountId().is_valid()) { |
| PA_LOG(ERROR) << "Empty user account. Auth attempt failed."; |
| RecordAuthResultFailure( |
| auth_attempt_type, |
| SmartLockMetricsRecorder::SmartLockAuthResultFailureReason:: |
| kEmptyUserAccount); |
| return; |
| } |
| |
| if (GetAccountId() != account_id) { |
| RecordAuthResultFailure( |
| auth_attempt_type, |
| SmartLockMetricsRecorder::SmartLockAuthResultFailureReason:: |
| kInvalidAccoundId); |
| |
| PA_LOG(ERROR) << "Check failed: " << GetAccountId().Serialize() << " vs " |
| << account_id.Serialize(); |
| return; |
| } |
| |
| auth_attempt_.reset(new EasyUnlockAuthAttempt(account_id, auth_attempt_type)); |
| if (!auth_attempt_->Start()) { |
| RecordAuthResultFailure( |
| auth_attempt_type, |
| SmartLockMetricsRecorder::SmartLockAuthResultFailureReason:: |
| kAuthAttemptCannotStart); |
| auth_attempt_.reset(); |
| } |
| |
| // TODO(tengs): We notify ProximityAuthSystem whenever unlock attempts are |
| // attempted. However, we ideally should refactor the auth attempt logic to |
| // the proximity_auth component. |
| if (proximity_auth_system_) |
| proximity_auth_system_->OnAuthAttempted(account_id); |
| } |
| |
| void EasyUnlockService::FinalizeUnlock(bool success) { |
| if (!auth_attempt_) |
| return; |
| |
| set_will_authenticate_using_easy_unlock(true); |
| auth_attempt_->FinalizeUnlock(GetAccountId(), success); |
| auth_attempt_.reset(); |
| // TODO(isherman): If observing screen unlock events, is there a race |
| // condition in terms of reading the service's state vs. the app setting the |
| // state? |
| |
| // Make sure that the lock screen is updated on failure. |
| if (!success) { |
| RecordEasyUnlockScreenUnlockEvent(EASY_UNLOCK_FAILURE); |
| HandleAuthFailure(GetAccountId()); |
| } |
| } |
| |
| void EasyUnlockService::FinalizeSignin(const std::string& key) { |
| if (!auth_attempt_) |
| return; |
| |
| std::string wrapped_secret = GetWrappedSecret(); |
| if (!wrapped_secret.empty()) |
| auth_attempt_->FinalizeSignin(GetAccountId(), wrapped_secret, key); |
| auth_attempt_.reset(); |
| |
| // Processing empty key is equivalent to auth cancellation. In this case the |
| // signin request will not actually be processed by login stack, so the lock |
| // screen state should be set from here. |
| if (key.empty()) { |
| HandleAuthFailure(GetAccountId()); |
| return; |
| } |
| |
| set_will_authenticate_using_easy_unlock(true); |
| } |
| |
| void EasyUnlockService::HandleAuthFailure(const AccountId& account_id) { |
| if (account_id != GetAccountId()) |
| return; |
| |
| if (!screenlock_state_handler_.get()) |
| return; |
| |
| screenlock_state_handler_->SetHardlockState( |
| EasyUnlockScreenlockStateHandler::LOGIN_FAILED); |
| } |
| |
| void EasyUnlockService::CheckCryptohomeKeysAndMaybeHardlock() { |
| const AccountId& account_id = GetAccountId(); |
| if (!account_id.is_valid() || !IsChromeOSLoginEnabled()) |
| return; |
| |
| const base::ListValue* device_list = GetRemoteDevices(); |
| std::set<std::string> paired_devices; |
| if (device_list) { |
| EasyUnlockDeviceKeyDataList parsed_paired; |
| EasyUnlockKeyManager::RemoteDeviceRefListToDeviceDataList(*device_list, |
| &parsed_paired); |
| for (const auto& device_key_data : parsed_paired) |
| paired_devices.insert(device_key_data.psk); |
| } |
| if (paired_devices.empty()) { |
| SetHardlockState(EasyUnlockScreenlockStateHandler::NO_PAIRING); |
| return; |
| } |
| |
| // No need to compare if a change is already recorded. |
| if (GetHardlockState() == EasyUnlockScreenlockStateHandler::PAIRING_CHANGED || |
| GetHardlockState() == EasyUnlockScreenlockStateHandler::PAIRING_ADDED) { |
| return; |
| } |
| |
| EasyUnlockKeyManager* key_manager = |
| UserSessionManager::GetInstance()->GetEasyUnlockKeyManager(); |
| DCHECK(key_manager); |
| |
| const user_manager::User* const user = |
| user_manager::UserManager::Get()->FindUser(account_id); |
| DCHECK(user); |
| key_manager->GetDeviceDataList( |
| UserContext(*user), |
| base::Bind(&EasyUnlockService::OnCryptohomeKeysFetchedForChecking, |
| weak_ptr_factory_.GetWeakPtr(), account_id, paired_devices)); |
| } |
| |
| void EasyUnlockService::Shutdown() { |
| if (shut_down_) |
| return; |
| shut_down_ = true; |
| |
| ShutdownInternal(); |
| |
| ResetScreenlockState(); |
| bluetooth_detector_.reset(); |
| proximity_auth_system_.reset(); |
| power_monitor_.reset(); |
| |
| weak_ptr_factory_.InvalidateWeakPtrs(); |
| } |
| |
| void EasyUnlockService::UpdateAppState() { |
| if (IsAllowed()) { |
| EnsureTpmKeyPresentIfNeeded(); |
| |
| if (proximity_auth_system_) |
| proximity_auth_system_->Start(); |
| |
| if (!power_monitor_) |
| power_monitor_.reset(new PowerMonitor(this)); |
| } else { |
| bool bluetooth_waking_up = false; |
| |
| // If the service is not allowed due to bluetooth not being detected just |
| // after system suspend is done, give bluetooth more time to be detected |
| // before resetting screenlock state. |
| bluetooth_waking_up = power_monitor_.get() && power_monitor_->waking_up() && |
| !bluetooth_detector_->IsPresent(); |
| |
| if (!bluetooth_waking_up) { |
| if (proximity_auth_system_) |
| proximity_auth_system_->Stop(); |
| |
| power_monitor_.reset(); |
| } |
| } |
| } |
| |
| void EasyUnlockService::ResetScreenlockState() { |
| screenlock_state_handler_.reset(); |
| auth_attempt_.reset(); |
| } |
| |
| void EasyUnlockService::SetScreenlockHardlockedState( |
| EasyUnlockScreenlockStateHandler::HardlockState state) { |
| if (GetScreenlockStateHandler()) { |
| screenlock_state_handler_->SetHardlockState(state); |
| screenlock_state_handler_->MaybeShowHardlockUI(); |
| } |
| if (state != EasyUnlockScreenlockStateHandler::NO_HARDLOCK) |
| auth_attempt_.reset(); |
| } |
| |
| void EasyUnlockService::OnBluetoothAdapterPresentChanged() { |
| UpdateAppState(); |
| } |
| |
| void EasyUnlockService::SetHardlockStateForUser( |
| const AccountId& account_id, |
| EasyUnlockScreenlockStateHandler::HardlockState state) { |
| DCHECK(account_id.is_valid()); |
| |
| PrefService* local_state = GetLocalState(); |
| if (!local_state) |
| return; |
| |
| // Disallow setting the hardlock state if the password is currently being |
| // forced. |
| if (GetScreenlockStateHandler() && |
| GetScreenlockStateHandler()->state() == |
| proximity_auth::ScreenlockState::PASSWORD_REAUTH) { |
| return; |
| } |
| |
| DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockHardlockState); |
| update->SetKey(account_id.GetUserEmail(), |
| base::Value(static_cast<int>(state))); |
| |
| if (GetAccountId() == account_id) |
| SetScreenlockHardlockedState(state); |
| } |
| |
| SmartLockMetricsRecorder::SmartLockAuthEventPasswordState |
| EasyUnlockService::GetSmartUnlockPasswordAuthEvent() const { |
| DCHECK(IsEnabled()); |
| |
| if (GetHardlockState() != EasyUnlockScreenlockStateHandler::NO_HARDLOCK) { |
| switch (GetHardlockState()) { |
| case EasyUnlockScreenlockStateHandler::NO_PAIRING: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kNoPairing; |
| case EasyUnlockScreenlockStateHandler::USER_HARDLOCK: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kUserHardlock; |
| case EasyUnlockScreenlockStateHandler::PAIRING_CHANGED: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kPairingChanged; |
| case EasyUnlockScreenlockStateHandler::LOGIN_FAILED: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kLoginFailed; |
| case EasyUnlockScreenlockStateHandler::PAIRING_ADDED: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kPairingAdded; |
| case EasyUnlockScreenlockStateHandler::LOGIN_DISABLED: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kLoginWithSmartLockDisabled; |
| default: |
| NOTREACHED(); |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kUnknownState; |
| } |
| } else if (!screenlock_state_handler()) { |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kUnknownState; |
| } else { |
| switch (screenlock_state_handler()->state()) { |
| case ScreenlockState::INACTIVE: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kServiceNotActive; |
| case ScreenlockState::NO_BLUETOOTH: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kNoBluetooth; |
| case ScreenlockState::BLUETOOTH_CONNECTING: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kBluetoothConnecting; |
| case ScreenlockState::NO_PHONE: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kCouldNotConnectToPhone; |
| case ScreenlockState::PHONE_NOT_AUTHENTICATED: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kNotAuthenticated; |
| case ScreenlockState::PHONE_LOCKED: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kPhoneLocked; |
| case ScreenlockState::RSSI_TOO_LOW: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kRssiTooLow; |
| case ScreenlockState::PHONE_LOCKED_AND_RSSI_TOO_LOW: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kPhoneLockedAndRssiTooLow; |
| case ScreenlockState::AUTHENTICATED: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kAuthenticatedPhone; |
| case ScreenlockState::PASSWORD_REAUTH: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kForcedReauth; |
| case ScreenlockState::PHONE_NOT_LOCKABLE: |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kPhoneNotLockable; |
| default: |
| NOTREACHED(); |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kUnknownState; |
| } |
| } |
| |
| NOTREACHED(); |
| return SmartLockMetricsRecorder::SmartLockAuthEventPasswordState:: |
| kUnknownState; |
| } |
| |
| EasyUnlockAuthEvent EasyUnlockService::GetPasswordAuthEvent() const { |
| DCHECK(IsEnabled()); |
| |
| if (GetHardlockState() != EasyUnlockScreenlockStateHandler::NO_HARDLOCK) { |
| switch (GetHardlockState()) { |
| case EasyUnlockScreenlockStateHandler::NO_HARDLOCK: |
| NOTREACHED(); |
| return EASY_UNLOCK_AUTH_EVENT_COUNT; |
| case EasyUnlockScreenlockStateHandler::NO_PAIRING: |
| return PASSWORD_ENTRY_NO_PAIRING; |
| case EasyUnlockScreenlockStateHandler::USER_HARDLOCK: |
| return PASSWORD_ENTRY_USER_HARDLOCK; |
| case EasyUnlockScreenlockStateHandler::PAIRING_CHANGED: |
| return PASSWORD_ENTRY_PAIRING_CHANGED; |
| case EasyUnlockScreenlockStateHandler::LOGIN_FAILED: |
| return PASSWORD_ENTRY_LOGIN_FAILED; |
| case EasyUnlockScreenlockStateHandler::PAIRING_ADDED: |
| return PASSWORD_ENTRY_PAIRING_ADDED; |
| case EasyUnlockScreenlockStateHandler::LOGIN_DISABLED: |
| return PASSWORD_ENTRY_LOGIN_DISABLED; |
| } |
| } else if (!screenlock_state_handler()) { |
| return PASSWORD_ENTRY_NO_SCREENLOCK_STATE_HANDLER; |
| } else { |
| switch (screenlock_state_handler()->state()) { |
| case ScreenlockState::INACTIVE: |
| return PASSWORD_ENTRY_SERVICE_NOT_ACTIVE; |
| case ScreenlockState::NO_BLUETOOTH: |
| return PASSWORD_ENTRY_NO_BLUETOOTH; |
| case ScreenlockState::BLUETOOTH_CONNECTING: |
| return PASSWORD_ENTRY_BLUETOOTH_CONNECTING; |
| case ScreenlockState::NO_PHONE: |
| return PASSWORD_ENTRY_NO_PHONE; |
| case ScreenlockState::PHONE_NOT_AUTHENTICATED: |
| return PASSWORD_ENTRY_PHONE_NOT_AUTHENTICATED; |
| case ScreenlockState::PHONE_LOCKED: |
| return PASSWORD_ENTRY_PHONE_LOCKED; |
| case ScreenlockState::PHONE_NOT_LOCKABLE: |
| return PASSWORD_ENTRY_PHONE_NOT_LOCKABLE; |
| case ScreenlockState::PHONE_UNSUPPORTED: |
| return PASSWORD_ENTRY_PHONE_UNSUPPORTED; |
| case ScreenlockState::RSSI_TOO_LOW: |
| return PASSWORD_ENTRY_RSSI_TOO_LOW; |
| case ScreenlockState::PHONE_LOCKED_AND_RSSI_TOO_LOW: |
| return PASSWORD_ENTRY_PHONE_LOCKED_AND_RSSI_TOO_LOW; |
| case ScreenlockState::AUTHENTICATED: |
| return PASSWORD_ENTRY_WITH_AUTHENTICATED_PHONE; |
| case ScreenlockState::PASSWORD_REAUTH: |
| return PASSWORD_ENTRY_FORCED_REAUTH; |
| } |
| } |
| |
| NOTREACHED(); |
| return EASY_UNLOCK_AUTH_EVENT_COUNT; |
| } |
| |
| void EasyUnlockService::SetProximityAuthDevices( |
| const AccountId& account_id, |
| const multidevice::RemoteDeviceRefList& remote_devices, |
| base::Optional<multidevice::RemoteDeviceRef> local_device) { |
| UMA_HISTOGRAM_COUNTS_100("SmartLock.EnabledDevicesCount", |
| remote_devices.size()); |
| |
| if (remote_devices.size() == 0) { |
| proximity_auth_system_.reset(); |
| return; |
| } |
| |
| if (!proximity_auth_system_) { |
| PA_LOG(VERBOSE) << "Creating ProximityAuthSystem."; |
| proximity_auth_system_.reset(new proximity_auth::ProximityAuthSystem( |
| GetType() == TYPE_SIGNIN |
| ? proximity_auth::ProximityAuthSystem::SIGN_IN |
| : proximity_auth::ProximityAuthSystem::SESSION_LOCK, |
| proximity_auth_client(), secure_channel_client_)); |
| } |
| |
| proximity_auth_system_->SetRemoteDevicesForUser(account_id, remote_devices, |
| local_device); |
| proximity_auth_system_->Start(); |
| } |
| |
| void EasyUnlockService::OnCryptohomeKeysFetchedForChecking( |
| const AccountId& account_id, |
| const std::set<std::string> paired_devices, |
| bool success, |
| const EasyUnlockDeviceKeyDataList& key_data_list) { |
| DCHECK(account_id.is_valid() && !paired_devices.empty()); |
| |
| if (!success) { |
| SetHardlockStateForUser(account_id, |
| EasyUnlockScreenlockStateHandler::NO_PAIRING); |
| return; |
| } |
| |
| std::set<std::string> devices_in_cryptohome; |
| for (const auto& device_key_data : key_data_list) |
| devices_in_cryptohome.insert(device_key_data.psk); |
| |
| if (paired_devices != devices_in_cryptohome || |
| GetHardlockState() == EasyUnlockScreenlockStateHandler::NO_PAIRING) { |
| SetHardlockStateForUser( |
| account_id, devices_in_cryptohome.empty() |
| ? EasyUnlockScreenlockStateHandler::PAIRING_ADDED |
| : EasyUnlockScreenlockStateHandler::PAIRING_CHANGED); |
| } |
| } |
| |
| void EasyUnlockService::PrepareForSuspend() { |
| if (screenlock_state_handler_ && screenlock_state_handler_->IsActive()) |
| UpdateScreenlockState(ScreenlockState::BLUETOOTH_CONNECTING); |
| if (proximity_auth_system_) |
| proximity_auth_system_->OnSuspend(); |
| } |
| |
| void EasyUnlockService::OnSuspendDone() { |
| if (proximity_auth_system_) |
| proximity_auth_system_->OnSuspendDone(); |
| } |
| |
| void EasyUnlockService::EnsureTpmKeyPresentIfNeeded() { |
| if (tpm_key_checked_ || GetType() != TYPE_REGULAR || GetAccountId().empty() || |
| GetHardlockState() == EasyUnlockScreenlockStateHandler::NO_PAIRING) { |
| return; |
| } |
| |
| // If this is called before the session is started, the chances are Chrome |
| // is restarting in order to apply user flags. Don't check TPM keys in this |
| // case. |
| if (!session_manager::SessionManager::Get() || |
| !session_manager::SessionManager::Get()->IsSessionStarted()) |
| return; |
| |
| // TODO(tbarzic): Set check_private_key only if previous sign-in attempt |
| // failed. |
| EasyUnlockTpmKeyManagerFactory::GetInstance()->Get(profile_)->PrepareTpmKey( |
| true /* check_private_key */, base::Closure()); |
| |
| tpm_key_checked_ = true; |
| } |
| |
| } // namespace chromeos |