blob: 694a51ef59d6cfc3c6d963b864c783a4cd159716 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <biod/auth_stack_manager_wrapper.h>
#include <map>
#include <utility>
#include <base/strings/stringprintf.h>
#include <base/test/task_environment.h>
#include <brillo/dbus/async_event_sequencer.h>
#include <brillo/dbus/mock_exported_object_manager.h>
#include <dbus/mock_bus.h>
#include <dbus/mock_exported_object.h>
#include <dbus/mock_object_proxy.h>
#include <dbus/object_path.h>
#include <dbus/property.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <biod/mock_auth_stack_manager.h>
#include <biod/mock_session_state_manager.h>
namespace biod {
namespace {
using brillo::BlobToString;
using testing::_;
using testing::ByMove;
using testing::Return;
using testing::ReturnRef;
using testing::SaveArg;
constexpr char kClientConnectionName[] = ":1.33";
constexpr char kTestUser[] = "testuser";
MATCHER_P(EqualsProto,
message,
"Match a proto Message equal to the matcher's argument.") {
std::string expected_serialized, actual_serialized;
message.SerializeToString(&expected_serialized);
arg.SerializeToString(&actual_serialized);
return expected_serialized == actual_serialized;
}
class AuthStackManagerWrapperTest : public ::testing::Test {
public:
void SetUp() override {
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
bus_ = new dbus::MockBus(options);
ON_CALL(*bus_, GetExportedObject)
.WillByDefault(
Invoke(this, &AuthStackManagerWrapperTest::GetExportedObject));
proxy_ =
new dbus::MockObjectProxy(bus_.get(), dbus::kDBusServiceName,
dbus::ObjectPath(dbus::kDBusServicePath));
ON_CALL(*bus_, GetObjectProxy(dbus::kDBusServiceName, _))
.WillByDefault(Return(proxy_.get()));
EXPECT_CALL(*proxy_, DoConnectToSignal(dbus::kDBusInterface, _, _, _))
.WillRepeatedly(
Invoke(this, &AuthStackManagerWrapperTest::ConnectToSignal));
auto mock_auth_stack_manager = std::make_unique<MockAuthStackManager>();
bio_manager_ = mock_auth_stack_manager.get();
EXPECT_CALL(*bio_manager_, SetEnrollScanDoneHandler)
.WillRepeatedly(SaveArg<0>(&on_enroll_scan_done));
EXPECT_CALL(*bio_manager_, SetAuthScanDoneHandler)
.WillRepeatedly(SaveArg<0>(&on_auth_scan_done));
EXPECT_CALL(*bio_manager_, SetSessionFailedHandler)
.WillRepeatedly(SaveArg<0>(&on_session_failed));
EXPECT_CALL(*bio_manager_, GetType)
.WillRepeatedly(Return(BIOMETRIC_TYPE_UNKNOWN));
object_manager_ =
std::make_unique<brillo::dbus_utils::MockExportedObjectManager>(
bus_, dbus::ObjectPath(kBiodServicePath));
session_manager_ = std::make_unique<MockSessionStateManager>();
EXPECT_CALL(*session_manager_, AddObserver).Times(1);
mock_bio_path_ = dbus::ObjectPath(
base::StringPrintf("%s/%s", kBiodServicePath, "MockAuthStackManager"));
auto sequencer =
base::MakeRefCounted<brillo::dbus_utils::AsyncEventSequencer>();
wrapper_.emplace(
std::move(mock_auth_stack_manager), object_manager_.get(),
session_manager_.get(), mock_bio_path_,
sequencer->GetHandler("Failed to register AuthStackManager", false));
}
protected:
scoped_refptr<dbus::MockBus> bus_;
scoped_refptr<dbus::MockObjectProxy> proxy_;
MockAuthStackManager* bio_manager_;
std::unique_ptr<brillo::dbus_utils::MockExportedObjectManager>
object_manager_;
dbus::ObjectPath mock_bio_path_;
std::map<std::string, scoped_refptr<dbus::MockExportedObject>>
exported_objects_;
std::unique_ptr<MockSessionStateManager> session_manager_;
std::optional<AuthStackManagerWrapper> wrapper_;
AuthStackManager::EnrollScanDoneCallback on_enroll_scan_done;
AuthStackManager::AuthScanDoneCallback on_auth_scan_done;
AuthStackManager::SessionFailedCallback on_session_failed;
MOCK_METHOD(void,
ResponseSender,
(std::unique_ptr<dbus::Response> response),
());
std::unique_ptr<dbus::Response> CallMethod(dbus::MethodCall* method_call);
std::unique_ptr<dbus::Response> StartEnrollSession(
dbus::ObjectPath* object_path);
std::unique_ptr<dbus::Response> CreateCredential(
const CreateCredentialRequest& request, CreateCredentialReply* reply);
std::unique_ptr<dbus::Response> StartAuthSession(
std::string user_id, dbus::ObjectPath* object_path);
void EmitNameOwnerChangedSignal(const std::string& name,
const std::string& old_owner,
const std::string& new_owner);
void ExpectStartEnrollSession();
void ExpectStartAuthSession(const std::string& user_id);
private:
std::map<std::string, dbus::ObjectProxy::SignalCallback> signal_callbacks_;
std::map<std::string, dbus::ExportedObject::MethodCallCallback>
method_callbacks_;
base::test::SingleThreadTaskEnvironment task_environment_;
void ConnectToSignal(
const std::string& interface_name,
const std::string& signal_name,
dbus::ObjectProxy::SignalCallback signal_callback,
dbus::ObjectProxy::OnConnectedCallback* on_connected_callback);
dbus::ExportedObject* GetExportedObject(const dbus::ObjectPath& object_path);
void ExportMethod(
const std::string& interface_name,
const std::string& method_name,
const dbus::ExportedObject::MethodCallCallback& method_call_callback,
dbus::ExportedObject::OnExportedCallback on_exported_callback);
bool ExportMethodAndBlock(
const std::string& interface_name,
const std::string& method_name,
const dbus::ExportedObject::MethodCallCallback& method_call_callback);
};
void AuthStackManagerWrapperTest::ConnectToSignal(
const std::string& interface_name,
const std::string& signal_name,
dbus::ObjectProxy::SignalCallback signal_callback,
dbus::ObjectProxy::OnConnectedCallback* on_connected_callback) {
EXPECT_EQ(interface_name, dbus::kDBusInterface);
signal_callbacks_[signal_name] = std::move(signal_callback);
task_environment_.GetMainThreadTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(std::move(*on_connected_callback), interface_name,
signal_name, true /* success */));
}
void AuthStackManagerWrapperTest::EmitNameOwnerChangedSignal(
const std::string& name,
const std::string& old_owner,
const std::string& new_owner) {
const auto it = signal_callbacks_.find("NameOwnerChanged");
ASSERT_TRUE(it != signal_callbacks_.end())
<< "Client didn't register for NameOwnerChanged signal";
dbus::Signal signal(dbus::kDBusInterface, "NameOwnerChanged");
dbus::MessageWriter writer(&signal);
writer.AppendString(name);
writer.AppendString(old_owner);
writer.AppendString(new_owner);
it->second.Run(&signal);
}
dbus::ExportedObject* AuthStackManagerWrapperTest::GetExportedObject(
const dbus::ObjectPath& object_path) {
auto iter = exported_objects_.find(object_path.value());
if (iter != exported_objects_.end()) {
return iter->second.get();
}
scoped_refptr<dbus::MockExportedObject> exported_object =
new dbus::MockExportedObject(bus_.get(), object_path);
exported_objects_[object_path.value()] = exported_object;
ON_CALL(*exported_object, ExportMethod)
.WillByDefault(Invoke(this, &AuthStackManagerWrapperTest::ExportMethod));
ON_CALL(*exported_object, ExportMethodAndBlock)
.WillByDefault(
Invoke(this, &AuthStackManagerWrapperTest::ExportMethodAndBlock));
return exported_object.get();
}
void AuthStackManagerWrapperTest::ExportMethod(
const std::string& interface_name,
const std::string& method_name,
const dbus::ExportedObject::MethodCallCallback& method_call_callback,
dbus::ExportedObject::OnExportedCallback on_exported_callback) {
std::string full_name = interface_name + "." + method_name;
method_callbacks_[full_name] = method_call_callback;
task_environment_.GetMainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(std::move(on_exported_callback), interface_name,
method_name, true /* success */));
}
bool AuthStackManagerWrapperTest::ExportMethodAndBlock(
const std::string& interface_name,
const std::string& method_name,
const dbus::ExportedObject::MethodCallCallback& method_call_callback) {
std::string full_name = interface_name + "." + method_name;
method_callbacks_[full_name] = method_call_callback;
return true;
}
std::unique_ptr<dbus::Response> AuthStackManagerWrapperTest::CallMethod(
dbus::MethodCall* method_call) {
std::string full_name =
method_call->GetInterface() + "." + method_call->GetMember();
std::unique_ptr<dbus::Response> response;
EXPECT_CALL(*this, ResponseSender)
.WillOnce([&response](std::unique_ptr<dbus::Response> result) {
response = std::move(result);
});
auto response_sender = base::BindOnce(
&AuthStackManagerWrapperTest::ResponseSender, base::Unretained(this));
method_call->SetSerial(1);
method_call->SetSender(kClientConnectionName);
auto iter = method_callbacks_.find(full_name);
EXPECT_TRUE(iter != method_callbacks_.end());
dbus::ExportedObject::MethodCallCallback& method_callback = iter->second;
method_callback.Run(method_call, std::move(response_sender));
return response;
}
std::unique_ptr<dbus::Response> AuthStackManagerWrapperTest::StartEnrollSession(
dbus::ObjectPath* object_path) {
dbus::MethodCall start_enroll_session(
kAuthStackManagerInterface, kAuthStackManagerStartEnrollSessionMethod);
auto response = CallMethod(&start_enroll_session);
if (response->GetMessageType() == dbus::Message::MESSAGE_METHOD_RETURN) {
dbus::MessageReader reader(response.get());
reader.PopObjectPath(object_path);
}
return response;
}
std::unique_ptr<dbus::Response> AuthStackManagerWrapperTest::CreateCredential(
const CreateCredentialRequest& request, CreateCredentialReply* reply) {
dbus::MethodCall create_credential(kAuthStackManagerInterface,
kAuthStackManagerCreateCredentialMethod);
dbus::MessageWriter writer(&create_credential);
writer.AppendProtoAsArrayOfBytes(request);
auto response = CallMethod(&create_credential);
if (response->GetMessageType() == dbus::Message::MESSAGE_METHOD_RETURN) {
dbus::MessageReader reader(response.get());
reader.PopArrayOfBytesAsProto(reply);
}
return response;
}
std::unique_ptr<dbus::Response> AuthStackManagerWrapperTest::StartAuthSession(
std::string user_id, dbus::ObjectPath* object_path) {
dbus::MethodCall start_auth_session(kAuthStackManagerInterface,
kAuthStackManagerStartAuthSessionMethod);
dbus::MessageWriter writer(&start_auth_session);
writer.AppendString(std::move(user_id));
auto response = CallMethod(&start_auth_session);
if (response->GetMessageType() == dbus::Message::MESSAGE_METHOD_RETURN) {
dbus::MessageReader reader(response.get());
reader.PopObjectPath(object_path);
}
return response;
}
void AuthStackManagerWrapperTest::ExpectStartEnrollSession() {
auto enroll_session = AuthStackManager::Session(
base::BindOnce(&MockAuthStackManager::EndEnrollSession,
bio_manager_->session_weak_factory_.GetWeakPtr()));
EXPECT_CALL(*bio_manager_, StartEnrollSession)
.WillOnce(Return(ByMove(std::move(enroll_session))));
}
void AuthStackManagerWrapperTest::ExpectStartAuthSession(
const std::string& user_id) {
auto auth_session = AuthStackManager::Session(
base::BindOnce(&MockAuthStackManager::EndAuthSession,
bio_manager_->session_weak_factory_.GetWeakPtr()));
EXPECT_CALL(*bio_manager_, StartAuthSession(user_id))
.WillOnce(Return(ByMove(std::move(auth_session))));
}
TEST_F(AuthStackManagerWrapperTest, TestStartEnrollSession) {
dbus::ObjectPath object_path;
ExpectStartEnrollSession();
auto response = StartEnrollSession(&object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
dbus::ObjectPath expected_object_path(mock_bio_path_.value() +
"/EnrollSession");
EXPECT_EQ(object_path, expected_object_path);
// Expect that enroll session will be finished on destruction of
// the enroll_session object. EXPECT_CALL is able to catch calls from
// enroll_session destructor which is called at the end of this
// test.
auto iter = exported_objects_.find(object_path.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, Unregister).Times(1);
EXPECT_CALL(*bio_manager_, EndEnrollSession).Times(1);
}
TEST_F(AuthStackManagerWrapperTest, TestStartEnrollSessionThenCancel) {
dbus::ObjectPath object_path;
ExpectStartEnrollSession();
auto response = StartEnrollSession(&object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
// Cancel enroll session.
auto iter = exported_objects_.find(object_path.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, Unregister).Times(1);
EXPECT_CALL(*bio_manager_, EndEnrollSession).Times(1);
dbus::MethodCall cancel_enroll_session(kEnrollSessionInterface,
kEnrollSessionCancelMethod);
auto cancel_response = CallMethod(&cancel_enroll_session);
// Make sure enroll session is not killed on destruction
// of the enroll_session object. EXPECT_CALL is able to catch calls from
// enroll_session destructor which is called at the end of this test.
EXPECT_CALL(*object, Unregister).Times(0);
EXPECT_CALL(*bio_manager_, EndEnrollSession).Times(0);
}
TEST_F(AuthStackManagerWrapperTest, TestEnrollSessionFinish) {
const brillo::Blob kAuthNonce(32, 1);
dbus::ObjectPath object_path;
ExpectStartEnrollSession();
auto response = StartEnrollSession(&object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
// Expect enroll session is active when not finished.
auto iter = exported_objects_.find(object_path.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, Unregister).Times(0);
EXPECT_CALL(*bio_manager_, EndEnrollSession).Times(0);
AuthStackManager::EnrollStatus enroll_status = {false, 50};
on_enroll_scan_done.Run(ScanResult::SCAN_RESULT_SUCCESS, enroll_status,
brillo::Blob());
// Finish enroll session.
EXPECT_CALL(*object, Unregister).Times(1);
EXPECT_CALL(*bio_manager_, EndEnrollSession).Times(1);
AuthStackManager::EnrollStatus enroll_status_finish = {true, 100};
on_enroll_scan_done.Run(ScanResult::SCAN_RESULT_SUCCESS, enroll_status_finish,
kAuthNonce);
}
TEST_F(AuthStackManagerWrapperTest, TestEnrollSessionSignal) {
const brillo::Blob kAuthNonce(32, 1);
dbus::ObjectPath object_path;
ExpectStartEnrollSession();
auto response = StartEnrollSession(&object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
// Expect enroll scan done signal is emitted when enroll session not finished.
auto iter = exported_objects_.find(mock_bio_path_.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, SendSignal).WillOnce([](dbus::Signal* signal) {
EXPECT_EQ(signal->GetInterface(), kAuthStackManagerInterface);
EXPECT_EQ(signal->GetMember(), kBiometricsManagerEnrollScanDoneSignal);
dbus::MessageReader reader(signal);
EnrollScanDone proto;
reader.PopArrayOfBytesAsProto(&proto);
EXPECT_FALSE(proto.done());
EXPECT_EQ(proto.scan_result(), ScanResult::SCAN_RESULT_SUCCESS);
EXPECT_EQ(proto.percent_complete(), 50);
EXPECT_TRUE(proto.auth_nonce().empty());
});
AuthStackManager::EnrollStatus enroll_status = {false, 50};
on_enroll_scan_done.Run(ScanResult::SCAN_RESULT_SUCCESS, enroll_status,
brillo::Blob());
// Finish enroll session.
EXPECT_CALL(*object, SendSignal)
.WillOnce([&kAuthNonce](dbus::Signal* signal) {
EXPECT_EQ(signal->GetInterface(), kAuthStackManagerInterface);
EXPECT_EQ(signal->GetMember(), kBiometricsManagerEnrollScanDoneSignal);
dbus::MessageReader reader(signal);
EnrollScanDone proto;
reader.PopArrayOfBytesAsProto(&proto);
EXPECT_TRUE(proto.done());
EXPECT_EQ(proto.scan_result(), ScanResult::SCAN_RESULT_SUCCESS);
EXPECT_EQ(proto.percent_complete(), 100);
EXPECT_EQ(proto.auth_nonce(), brillo::BlobToString(kAuthNonce));
});
AuthStackManager::EnrollStatus enroll_status_finish = {true, 100};
on_enroll_scan_done.Run(ScanResult::SCAN_RESULT_SUCCESS, enroll_status_finish,
kAuthNonce);
}
TEST_F(AuthStackManagerWrapperTest, TestOnEnrollScanDoneWithoutActiveSession) {
const brillo::Blob kAuthNonce(32, 1);
auto iter = exported_objects_.find(mock_bio_path_.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
// Expect that no signal will be sent when there is no enroll session.
EXPECT_CALL(*object, SendSignal).Times(0);
AuthStackManager::EnrollStatus enroll_status_finish = {true, 100};
on_enroll_scan_done.Run(ScanResult::SCAN_RESULT_SUCCESS, enroll_status_finish,
kAuthNonce);
}
TEST_F(AuthStackManagerWrapperTest, TestStartEnrollSessionFailed) {
dbus::ObjectPath object_path;
// Empty enroll session indicates that we were not able to start
// enroll session.
EXPECT_CALL(*bio_manager_, StartEnrollSession)
.WillOnce(Return(ByMove(AuthStackManager::Session())));
auto response = StartEnrollSession(&object_path);
EXPECT_TRUE(response->GetMessageType() == dbus::Message::MESSAGE_ERROR);
}
TEST_F(AuthStackManagerWrapperTest, TestOnSessionFailedEndsEnrollSession) {
dbus::ObjectPath object_path;
ExpectStartEnrollSession();
auto response = StartEnrollSession(&object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
// Fail enroll session.
auto iter = exported_objects_.find(object_path.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, Unregister).Times(1);
EXPECT_CALL(*bio_manager_, EndEnrollSession).Times(1);
on_session_failed.Run();
// Make sure enroll session is not killed on destruction
// of the enroll_session object. EXPECT_CALL is able to catch calls from
// enroll_session destructor which is called at the end of this test.
EXPECT_CALL(*object, Unregister).Times(0);
EXPECT_CALL(*bio_manager_, EndEnrollSession).Times(0);
}
TEST_F(AuthStackManagerWrapperTest, TestEnrollOnSessionFailedSendSignal) {
dbus::ObjectPath object_path;
ExpectStartEnrollSession();
auto response = StartEnrollSession(&object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
auto iter = exported_objects_.find(mock_bio_path_.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, SendSignal).WillOnce([](dbus::Signal* signal) {
EXPECT_EQ(signal->GetInterface(), kAuthStackManagerInterface);
EXPECT_EQ(signal->GetMember(), kBiometricsManagerSessionFailedSignal);
});
// Fail enroll session.
on_session_failed.Run();
}
TEST_F(AuthStackManagerWrapperTest, TestEnrollSessionOwnerDies) {
dbus::ObjectPath object_path;
ExpectStartEnrollSession();
auto response = StartEnrollSession(&object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
// Fail enroll session.
auto iter = exported_objects_.find(object_path.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, Unregister).Times(1);
EXPECT_CALL(*bio_manager_, EndEnrollSession).Times(1);
EmitNameOwnerChangedSignal(kClientConnectionName, kClientConnectionName, "");
// Make sure enroll session is not killed on destruction
// of the enroll_session object. EXPECT_CALL is able to catch calls from
// enroll_session destructor which is called at the end of this test.
EXPECT_CALL(*object, Unregister).Times(0);
EXPECT_CALL(*bio_manager_, EndEnrollSession).Times(0);
}
TEST_F(AuthStackManagerWrapperTest, TestStartAuthSession) {
dbus::ObjectPath object_path;
ExpectStartAuthSession(kTestUser);
auto response = StartAuthSession(kTestUser, &object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
dbus::ObjectPath expected_object_path(mock_bio_path_.value() +
"/AuthSession");
EXPECT_EQ(object_path, expected_object_path);
// Expect that auth session will be killed on destruction of the auth_sesson
// object. EXPECT_CALL is able to catch calls from auth_session destructor
// which is called at the end of this test.
auto iter = exported_objects_.find(object_path.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, Unregister).Times(1);
EXPECT_CALL(*bio_manager_, EndAuthSession).Times(1);
}
TEST_F(AuthStackManagerWrapperTest, TestStartAuthSessionThenEnd) {
dbus::ObjectPath object_path;
ExpectStartAuthSession(kTestUser);
auto response = StartAuthSession(kTestUser, &object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
// Cancel auth session.
auto iter = exported_objects_.find(object_path.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, Unregister).Times(1);
EXPECT_CALL(*bio_manager_, EndAuthSession).Times(1);
dbus::MethodCall end_auth_session(kAuthSessionInterface,
kAuthSessionEndMethod);
auto cancel_response = CallMethod(&end_auth_session);
// Make sure auth session is not killed on destruction of the auth_session
// object. EXPECT_CALL is able to catch calls from auth_session destructor
// which is called at the end of this test.
EXPECT_CALL(*object, Unregister).Times(0);
EXPECT_CALL(*bio_manager_, EndAuthSession).Times(0);
}
TEST_F(AuthStackManagerWrapperTest, TestStartAuthSessionSuccess) {
const brillo::Blob kAuthNonce(32, 1);
dbus::ObjectPath object_path;
ExpectStartAuthSession(kTestUser);
auto response = StartAuthSession(kTestUser, &object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
// Expect that calling OnAuthScanDone doesn't end auth session.
auto iter = exported_objects_.find(object_path.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, Unregister).Times(0);
EXPECT_CALL(*bio_manager_, EndAuthSession).Times(0);
on_auth_scan_done.Run(kAuthNonce);
// Expect that auth session will be killed on destruction of the auth_session
// object. EXPECT_CALL is able to catch calls from auth_session destructor
// which is called at the end of this test.
EXPECT_CALL(*object, Unregister).Times(1);
EXPECT_CALL(*bio_manager_, EndAuthSession).Times(1);
}
TEST_F(AuthStackManagerWrapperTest, TestStartAuthSessionSuccessSignal) {
const brillo::Blob kAuthNonce(32, 1);
dbus::ObjectPath object_path;
ExpectStartAuthSession(kTestUser);
auto response = StartAuthSession(kTestUser, &object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
// Check signal contents.
auto iter = exported_objects_.find(mock_bio_path_.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, SendSignal).WillOnce([kAuthNonce](dbus::Signal* signal) {
EXPECT_EQ(signal->GetInterface(), kAuthStackManagerInterface);
EXPECT_EQ(signal->GetMember(), kBiometricsManagerAuthScanDoneSignal);
dbus::MessageReader reader(signal);
AuthScanDone proto;
reader.PopArrayOfBytesAsProto(&proto);
EXPECT_EQ(proto.auth_nonce(), brillo::BlobToString(kAuthNonce));
});
on_auth_scan_done.Run(kAuthNonce);
}
TEST_F(AuthStackManagerWrapperTest, TestStartAuthSessionFailed) {
dbus::ObjectPath object_path;
// Empty auth session indicates that we were not able to start
// enroll session.
EXPECT_CALL(*bio_manager_, StartAuthSession(kTestUser))
.WillOnce(Return(ByMove(AuthStackManager::Session())));
auto response = StartAuthSession(kTestUser, &object_path);
EXPECT_TRUE(response->GetMessageType() == dbus::Message::MESSAGE_ERROR);
}
TEST_F(AuthStackManagerWrapperTest, TestOnSessionFailedEndsAuthSession) {
dbus::ObjectPath object_path;
ExpectStartAuthSession(kTestUser);
auto response = StartAuthSession(kTestUser, &object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
// Cancel auth session.
auto iter = exported_objects_.find(object_path.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, Unregister).Times(1);
EXPECT_CALL(*bio_manager_, EndAuthSession).Times(1);
on_session_failed.Run();
// Make sure auth session is not killed on destruction of the auth_session
// object. EXPECT_CALL is able to catch calls from auth_session destructor
// which is called at the end of this test.
EXPECT_CALL(*object, Unregister).Times(0);
EXPECT_CALL(*bio_manager_, EndAuthSession).Times(0);
}
TEST_F(AuthStackManagerWrapperTest, TestAuthOnSessionFailedSendsSignal) {
dbus::ObjectPath object_path;
ExpectStartAuthSession(kTestUser);
auto response = StartAuthSession(kTestUser, &object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
auto iter = exported_objects_.find(mock_bio_path_.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, SendSignal).WillOnce([](dbus::Signal* signal) {
EXPECT_EQ(signal->GetInterface(), kAuthStackManagerInterface);
EXPECT_EQ(signal->GetMember(), kBiometricsManagerSessionFailedSignal);
});
// Fail enroll session.
on_session_failed.Run();
}
TEST_F(AuthStackManagerWrapperTest, TestAuthSessionOwnerDies) {
dbus::ObjectPath object_path;
ExpectStartAuthSession(kTestUser);
auto response = StartAuthSession(kTestUser, &object_path);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
// Cancel auth session.
auto iter = exported_objects_.find(object_path.value());
ASSERT_TRUE(iter != exported_objects_.end());
scoped_refptr<dbus::MockExportedObject> object = iter->second;
EXPECT_CALL(*object, Unregister).Times(1);
EXPECT_CALL(*bio_manager_, EndAuthSession).Times(1);
EmitNameOwnerChangedSignal(kClientConnectionName, kClientConnectionName, "");
// Make sure auth session is not killed on destruction of the auth_session
// object. EXPECT_CALL is able to catch calls from auth_session destructor
// which is called at the end of this test.
EXPECT_CALL(*object, Unregister).Times(0);
EXPECT_CALL(*bio_manager_, EndAuthSession).Times(0);
}
TEST_F(AuthStackManagerWrapperTest, TestCreateCredential) {
const std::string kUserId("testuser");
const brillo::Blob kGscNonce(32, 1);
const brillo::Blob kEncryptedLabelSeed(32, 2);
const brillo::Blob kPubInX(32, 3), kPubInY(32, 4);
const brillo::Blob kEncryptedSecret(32, 5);
const brillo::Blob kPubOutX(32, 6), kPubOutY(32, 7);
const std::string kRecordId("record_id");
CreateCredentialRequest request;
request.set_user_id(kUserId);
request.set_gsc_nonce(BlobToString(kGscNonce));
request.set_encrypted_label_seed(BlobToString(kEncryptedLabelSeed));
request.mutable_pub()->set_x(BlobToString(kPubInX));
request.mutable_pub()->set_y(BlobToString(kPubInY));
CreateCredentialReply reply;
reply.set_status(CreateCredentialReply::SUCCESS);
reply.set_encrypted_secret(BlobToString(kEncryptedSecret));
reply.mutable_pub()->set_x(BlobToString(kPubOutX));
reply.mutable_pub()->set_y(BlobToString(kPubOutY));
reply.set_record_id(kRecordId);
EXPECT_CALL(*bio_manager_, CreateCredential(EqualsProto(request)))
.WillOnce(Return(reply));
CreateCredentialReply returned_reply;
auto response = CreateCredential(request, &returned_reply);
EXPECT_TRUE(response->GetMessageType() ==
dbus::Message::MESSAGE_METHOD_RETURN);
EXPECT_THAT(returned_reply, EqualsProto(reply));
}
TEST_F(AuthStackManagerWrapperTest, TestOnUserLoggedInLoggedOut) {
const std::string kUserId("testuser");
EXPECT_CALL(*bio_manager_, OnUserLoggedIn(kUserId));
EXPECT_CALL(*bio_manager_, OnUserLoggedOut);
wrapper_->OnUserLoggedIn(kUserId, true);
wrapper_->OnUserLoggedOut();
}
} // namespace
} // namespace biod