blob: 0b672d6a16c8df5375422394570e55481f1fac7e [file] [log] [blame]
// 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/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) {
PowerManagerClient::Get()->AddObserver(this);
}
~PowerMonitor() override { PowerManagerClient::Get()->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