blob: 6db8565be73c8ffeaa439fb17c8af07f337343fc [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 "components/proximity_auth/proximity_auth_system.h"
#include "base/command_line.h"
#include "base/test/simple_test_clock.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/cryptauth/remote_device.h"
#include "components/proximity_auth/fake_lock_handler.h"
#include "components/proximity_auth/fake_remote_device_life_cycle.h"
#include "components/proximity_auth/logging/logging.h"
#include "components/proximity_auth/mock_proximity_auth_client.h"
#include "components/proximity_auth/proximity_auth_profile_pref_manager.h"
#include "components/proximity_auth/switches.h"
#include "components/proximity_auth/unlock_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using cryptauth::RemoteDevice;
using cryptauth::RemoteDeviceList;
using testing::AnyNumber;
using testing::AtLeast;
using testing::InSequence;
using testing::NiceMock;
using testing::NotNull;
using testing::Return;
using testing::SaveArg;
using testing::_;
namespace proximity_auth {
namespace {
const char kUser1[] = "user1";
const char kUser2[] = "user2";
const int64_t kLastPasswordEntryTimestampMs = 123456L;
const int64_t kTimestampBeforeReauthMs = 123457L;
const int64_t kTimestampAfterReauthMs = 123457890123L;
void CompareRemoteDeviceLists(const RemoteDeviceList& list1,
const RemoteDeviceList& list2) {
ASSERT_EQ(list1.size(), list2.size());
for (size_t i = 0; i < list1.size(); ++i) {
RemoteDevice device1 = list1[i];
RemoteDevice device2 = list2[i];
EXPECT_EQ(device1.public_key, device2.public_key);
}
}
// Creates a RemoteDevice object for |user_id| with |name|.
RemoteDevice CreateRemoteDevice(const std::string& user_id,
const std::string& name) {
return RemoteDevice(user_id, name + "_pk", name, name + "_btaddr",
name + "_psk", true /* unlock_key */,
true /* supports_mobile_hotspot */,
0 /* last_update_time_millis */);
}
// Mock implementation of UnlockManager.
class MockUnlockManager : public UnlockManager {
public:
MockUnlockManager() {}
~MockUnlockManager() override {}
MOCK_METHOD0(IsUnlockAllowed, bool());
MOCK_METHOD1(SetRemoteDeviceLifeCycle, void(RemoteDeviceLifeCycle*));
MOCK_METHOD0(OnLifeCycleStateChanged, void());
MOCK_METHOD1(OnAuthAttempted, void(mojom::AuthType));
private:
DISALLOW_COPY_AND_ASSIGN(MockUnlockManager);
};
// Mock implementation of ProximityAuthProfilePrefManager.
class MockProximityAuthPrefManager : public ProximityAuthProfilePrefManager {
public:
MockProximityAuthPrefManager() : ProximityAuthProfilePrefManager(nullptr) {}
~MockProximityAuthPrefManager() override {}
MOCK_CONST_METHOD0(GetLastPasswordEntryTimestampMs, int64_t());
private:
DISALLOW_COPY_AND_ASSIGN(MockProximityAuthPrefManager);
};
// Harness for ProximityAuthSystem to make it testable.
class TestableProximityAuthSystem : public ProximityAuthSystem {
public:
TestableProximityAuthSystem(ScreenlockType screenlock_type,
ProximityAuthClient* proximity_auth_client,
std::unique_ptr<UnlockManager> unlock_manager,
base::Clock* clock,
ProximityAuthPrefManager* pref_manager)
: ProximityAuthSystem(screenlock_type,
proximity_auth_client,
std::move(unlock_manager),
clock,
pref_manager),
life_cycle_(nullptr) {}
~TestableProximityAuthSystem() override {}
FakeRemoteDeviceLifeCycle* life_cycle() { return life_cycle_; }
private:
std::unique_ptr<RemoteDeviceLifeCycle> CreateRemoteDeviceLifeCycle(
const RemoteDevice& remote_device) override {
std::unique_ptr<FakeRemoteDeviceLifeCycle> life_cycle(
new FakeRemoteDeviceLifeCycle(remote_device));
life_cycle_ = life_cycle.get();
return std::move(life_cycle);
}
FakeRemoteDeviceLifeCycle* life_cycle_;
DISALLOW_COPY_AND_ASSIGN(TestableProximityAuthSystem);
};
} // namespace
class ProximityAuthSystemTest : public testing::Test {
protected:
ProximityAuthSystemTest()
: pref_manager_(new NiceMock<MockProximityAuthPrefManager>()),
task_runner_(new base::TestSimpleTaskRunner()),
thread_task_runner_handle_(task_runner_) {}
void SetUp() override {
user1_remote_devices_.push_back(
CreateRemoteDevice(kUser1, "user1_device1"));
user1_remote_devices_.push_back(
CreateRemoteDevice(kUser1, "user1_device2"));
user2_remote_devices_.push_back(
CreateRemoteDevice(kUser2, "user2_device1"));
user2_remote_devices_.push_back(
CreateRemoteDevice(kUser2, "user2_device2"));
user2_remote_devices_.push_back(
CreateRemoteDevice(kUser2, "user2_device3"));
InitProximityAuthSystem(ProximityAuthSystem::SESSION_LOCK);
proximity_auth_system_->SetRemoteDevicesForUser(
AccountId::FromUserEmail(kUser1), user1_remote_devices_);
proximity_auth_system_->Start();
LockScreen();
}
void TearDown() override { UnlockScreen(); }
void InitProximityAuthSystem(ProximityAuthSystem::ScreenlockType type) {
std::unique_ptr<MockUnlockManager> unlock_manager(
new NiceMock<MockUnlockManager>());
unlock_manager_ = unlock_manager.get();
clock_.SetNow(base::Time::FromJavaTime(kTimestampBeforeReauthMs));
ON_CALL(*pref_manager_, GetLastPasswordEntryTimestampMs())
.WillByDefault(Return(kLastPasswordEntryTimestampMs));
proximity_auth_system_.reset(new TestableProximityAuthSystem(
type, &proximity_auth_client_, std::move(unlock_manager), &clock_,
pref_manager_.get()));
}
void LockScreen() {
ScreenlockBridge::Get()->SetFocusedUser(AccountId());
ScreenlockBridge::Get()->SetLockHandler(&lock_handler_);
}
void FocusUser(const std::string& user_id) {
ScreenlockBridge::Get()->SetFocusedUser(AccountId::FromUserEmail(user_id));
}
void UnlockScreen() { ScreenlockBridge::Get()->SetLockHandler(nullptr); }
void SimulateSuspend() {
proximity_auth_system_->OnSuspend();
proximity_auth_system_->OnSuspendDone();
task_runner_->RunUntilIdle();
}
FakeRemoteDeviceLifeCycle* life_cycle() {
return proximity_auth_system_->life_cycle();
}
FakeLockHandler lock_handler_;
NiceMock<MockProximityAuthClient> proximity_auth_client_;
std::unique_ptr<TestableProximityAuthSystem> proximity_auth_system_;
MockUnlockManager* unlock_manager_;
base::SimpleTestClock clock_;
std::unique_ptr<MockProximityAuthPrefManager> pref_manager_;
RemoteDeviceList user1_remote_devices_;
RemoteDeviceList user2_remote_devices_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle thread_task_runner_handle_;
private:
ScopedDisableLoggingForTesting disable_logging_;
DISALLOW_COPY_AND_ASSIGN(ProximityAuthSystemTest);
};
TEST_F(ProximityAuthSystemTest, SetRemoteDevicesForUser_NotStarted) {
InitProximityAuthSystem(ProximityAuthSystem::SESSION_LOCK);
AccountId account1 = AccountId::FromUserEmail(kUser1);
AccountId account2 = AccountId::FromUserEmail(kUser2);
proximity_auth_system_->SetRemoteDevicesForUser(account1,
user1_remote_devices_);
proximity_auth_system_->SetRemoteDevicesForUser(account2,
user2_remote_devices_);
CompareRemoteDeviceLists(
user1_remote_devices_,
proximity_auth_system_->GetRemoteDevicesForUser(account1));
CompareRemoteDeviceLists(
user2_remote_devices_,
proximity_auth_system_->GetRemoteDevicesForUser(account2));
CompareRemoteDeviceLists(
RemoteDeviceList(),
proximity_auth_system_->GetRemoteDevicesForUser(
AccountId::FromUserEmail("non_existent_user@google.com")));
}
TEST_F(ProximityAuthSystemTest, SetRemoteDevicesForUser_Started) {
InitProximityAuthSystem(ProximityAuthSystem::SESSION_LOCK);
AccountId account1 = AccountId::FromUserEmail(kUser1);
AccountId account2 = AccountId::FromUserEmail(kUser2);
proximity_auth_system_->SetRemoteDevicesForUser(account1,
user1_remote_devices_);
proximity_auth_system_->Start();
proximity_auth_system_->SetRemoteDevicesForUser(account2,
user2_remote_devices_);
CompareRemoteDeviceLists(
user1_remote_devices_,
proximity_auth_system_->GetRemoteDevicesForUser(account1));
CompareRemoteDeviceLists(
user2_remote_devices_,
proximity_auth_system_->GetRemoteDevicesForUser(account2));
}
TEST_F(ProximityAuthSystemTest, FocusRegisteredUser) {
EXPECT_FALSE(life_cycle());
EXPECT_EQ(std::string(),
ScreenlockBridge::Get()->focused_account_id().GetUserEmail());
RemoteDeviceLifeCycle* unlock_manager_life_cycle = nullptr;
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(_))
.WillOnce(SaveArg<0>(&unlock_manager_life_cycle));
FocusUser(kUser1);
EXPECT_EQ(life_cycle(), unlock_manager_life_cycle);
EXPECT_TRUE(life_cycle());
EXPECT_TRUE(life_cycle()->started());
EXPECT_EQ(kUser1, life_cycle()->GetRemoteDevice().user_id);
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(nullptr))
.Times(AtLeast(1));
}
TEST_F(ProximityAuthSystemTest, FocusUnregisteredUser) {
EXPECT_FALSE(life_cycle());
EXPECT_EQ(std::string(),
ScreenlockBridge::Get()->focused_account_id().GetUserEmail());
EXPECT_FALSE(life_cycle());
FocusUser(kUser2);
EXPECT_FALSE(life_cycle());
}
TEST_F(ProximityAuthSystemTest, ToggleFocus_RegisteredUsers) {
proximity_auth_system_->SetRemoteDevicesForUser(
AccountId::FromUserEmail(kUser2), user2_remote_devices_);
RemoteDeviceLifeCycle* life_cycle1 = nullptr;
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(_))
.WillOnce(SaveArg<0>(&life_cycle1));
FocusUser(kUser1);
EXPECT_EQ(kUser1, life_cycle1->GetRemoteDevice().user_id);
RemoteDeviceLifeCycle* life_cycle2 = nullptr;
{
InSequence sequence;
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(nullptr))
.Times(AtLeast(1));
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(_))
.WillOnce(SaveArg<0>(&life_cycle2));
}
FocusUser(kUser2);
EXPECT_EQ(kUser2, life_cycle2->GetRemoteDevice().user_id);
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(nullptr))
.Times(AtLeast(1));
}
TEST_F(ProximityAuthSystemTest, ToggleFocus_UnregisteredUsers) {
FocusUser(kUser2);
EXPECT_FALSE(life_cycle());
FocusUser("unregistered-user");
EXPECT_FALSE(life_cycle());
FocusUser(kUser2);
EXPECT_FALSE(life_cycle());
}
TEST_F(ProximityAuthSystemTest, ToggleFocus_RegisteredAndUnregisteredUsers) {
// Focus User 1, who is registered. This should create a new life cycle.
RemoteDeviceLifeCycle* life_cycle = nullptr;
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(_))
.WillOnce(SaveArg<0>(&life_cycle));
FocusUser(kUser1);
EXPECT_EQ(kUser1, life_cycle->GetRemoteDevice().user_id);
// User 2 has not been registered yet, so focusing them should not create a
// new life cycle.
life_cycle = nullptr;
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(nullptr));
FocusUser(kUser2);
EXPECT_FALSE(life_cycle);
// Focusing back to User 1 should recreate a new life cycle.
life_cycle = nullptr;
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(_))
.WillOnce(SaveArg<0>(&life_cycle));
FocusUser(kUser1);
EXPECT_EQ(kUser1, life_cycle->GetRemoteDevice().user_id);
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(nullptr))
.Times(AtLeast(1));
}
TEST_F(ProximityAuthSystemTest, ToggleFocus_SameUserRefocused) {
RemoteDeviceLifeCycle* life_cycle = nullptr;
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(_))
.WillOnce(SaveArg<0>(&life_cycle));
FocusUser(kUser1);
EXPECT_EQ(kUser1, life_cycle->GetRemoteDevice().user_id);
// Focusing the user again should be idempotent. The screenlock UI may call
// focus on the same user multiple times.
// SetRemoteDeviceLifeCycle() is only expected to be called once.
FocusUser(kUser1);
// The RemoteDeviceLifeCycle should be nulled upon destruction.
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(nullptr))
.Times(AtLeast(1));
}
TEST_F(ProximityAuthSystemTest, RestartSystem_UnregisteredUserFocused) {
FocusUser(kUser2);
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(nullptr))
.Times(AnyNumber());
proximity_auth_system_->Stop();
proximity_auth_system_->Start();
EXPECT_FALSE(life_cycle());
}
TEST_F(ProximityAuthSystemTest, StopSystem_RegisteredUserFocused) {
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(NotNull()));
FocusUser(kUser1);
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(nullptr))
.Times(AtLeast(1));
proximity_auth_system_->Stop();
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(NotNull()));
proximity_auth_system_->Start();
EXPECT_EQ(kUser1, life_cycle()->GetRemoteDevice().user_id);
}
TEST_F(ProximityAuthSystemTest, OnLifeCycleStateChanged) {
FocusUser(kUser1);
EXPECT_CALL(*unlock_manager_, OnLifeCycleStateChanged());
life_cycle()->ChangeState(RemoteDeviceLifeCycle::State::FINDING_CONNECTION);
EXPECT_CALL(*unlock_manager_, OnLifeCycleStateChanged());
life_cycle()->ChangeState(RemoteDeviceLifeCycle::State::AUTHENTICATING);
EXPECT_CALL(*unlock_manager_, OnLifeCycleStateChanged());
life_cycle()->ChangeState(
RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED);
}
TEST_F(ProximityAuthSystemTest, OnAuthAttempted) {
FocusUser(kUser1);
EXPECT_CALL(*unlock_manager_, OnAuthAttempted(_));
proximity_auth_system_->OnAuthAttempted(AccountId::FromUserEmail(kUser1));
}
TEST_F(ProximityAuthSystemTest, Suspend_ScreenUnlocked) {
UnlockScreen();
EXPECT_FALSE(life_cycle());
SimulateSuspend();
EXPECT_FALSE(life_cycle());
}
TEST_F(ProximityAuthSystemTest, Suspend_UnregisteredUserFocused) {
SimulateSuspend();
EXPECT_FALSE(life_cycle());
}
TEST_F(ProximityAuthSystemTest, Suspend_RegisteredUserFocused) {
FocusUser(kUser1);
{
InSequence sequence;
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(nullptr))
.Times(AtLeast(1));
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(NotNull()));
SimulateSuspend();
}
EXPECT_EQ(kUser1, life_cycle()->GetRemoteDevice().user_id);
EXPECT_CALL(*unlock_manager_, SetRemoteDeviceLifeCycle(nullptr))
.Times(AtLeast(1));
}
TEST_F(ProximityAuthSystemTest, ForcePasswordReauth) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
proximity_auth::switches::kEnableForcePasswordReauth);
ON_CALL(*pref_manager_, GetLastPasswordEntryTimestampMs())
.WillByDefault(Return(kTimestampAfterReauthMs));
EXPECT_CALL(proximity_auth_client_,
UpdateScreenlockState(ScreenlockState::PASSWORD_REAUTH));
FocusUser(kUser1);
EXPECT_FALSE(life_cycle());
}
} // namespace proximity_auth