fido: initial tests for Windows WebAuthn API integration
This adds a fake implementation of WinWebAuthnApi along with a scoped override of WinWebAuthnApi::GetDefault, as well as a test to verify USB authenticator instantiation depending on API availability and feature flag state. Bug: 898718 Change-Id: Iff3a317b4540986775a40fc872754ba0571ae88a Reviewed-on: https://chromium-review.googlesource.com/c/1316839 Commit-Queue: Martin Kreichgauer <martinkr@chromium.org> Reviewed-by: Jun Choi <hongjunchoi@chromium.org> Reviewed-by: Adam Langley <agl@chromium.org> Cr-Commit-Position: refs/heads/master@{#606254}
This commit is contained in:

committed by
Commit Bot

parent
aa8e030a25
commit
df06312dad
@ -143,7 +143,6 @@ component("fido") {
|
||||
defines = [ "IS_DEVICE_FIDO_IMPL" ]
|
||||
|
||||
deps = [
|
||||
":buildflags",
|
||||
"//components/apdu",
|
||||
"//components/cbor",
|
||||
"//crypto",
|
||||
@ -156,6 +155,7 @@ component("fido") {
|
||||
]
|
||||
|
||||
public_deps = [
|
||||
":buildflags",
|
||||
"//base",
|
||||
"//device/bluetooth",
|
||||
"//services/device/public/mojom",
|
||||
@ -307,6 +307,8 @@ source_set("test_support") {
|
||||
"//device/fido",
|
||||
"//mojo/public/cpp/bindings",
|
||||
"//services/device/public/mojom",
|
||||
"//services/service_manager/public/cpp",
|
||||
"//services/service_manager/public/mojom",
|
||||
"//testing/gmock",
|
||||
"//testing/gtest",
|
||||
]
|
||||
@ -329,4 +331,11 @@ source_set("test_support") {
|
||||
"mac/scoped_touch_id_test_environment.mm",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_win && use_win_webauthn_api) {
|
||||
sources += [
|
||||
"win/fake_webauthn_api.cc",
|
||||
"win/fake_webauthn_api.h",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -180,6 +180,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
|
||||
return transport_availability_info_;
|
||||
}
|
||||
|
||||
const AuthenticatorMap& AuthenticatorsForTesting() {
|
||||
return active_authenticators_;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Subclasses implement this method to dispatch their request onto the given
|
||||
// FidoAuthenticator. The FidoAuthenticator is owned by this
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "base/test/scoped_task_environment.h"
|
||||
#include "device/bluetooth/bluetooth_adapter_factory.h"
|
||||
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
|
||||
#include "device/fido/buildflags.h"
|
||||
#include "device/fido/fake_fido_discovery.h"
|
||||
#include "device/fido/fido_constants.h"
|
||||
#include "device/fido/fido_device.h"
|
||||
@ -174,14 +175,18 @@ class FakeFidoAuthenticator : public FidoDeviceAuthenticator {
|
||||
|
||||
class FakeFidoRequestHandler : public FidoRequestHandler<std::vector<uint8_t>> {
|
||||
public:
|
||||
FakeFidoRequestHandler(const base::flat_set<FidoTransportProtocol>& protocols,
|
||||
FakeFidoRequestHandler(service_manager::Connector* connector,
|
||||
const base::flat_set<FidoTransportProtocol>& protocols,
|
||||
FakeHandlerCallback callback)
|
||||
: FidoRequestHandler(nullptr /* connector */,
|
||||
protocols,
|
||||
std::move(callback)),
|
||||
: FidoRequestHandler(connector, protocols, std::move(callback)),
|
||||
weak_factory_(this) {
|
||||
Start();
|
||||
}
|
||||
FakeFidoRequestHandler(const base::flat_set<FidoTransportProtocol>& protocols,
|
||||
FakeHandlerCallback callback)
|
||||
: FakeFidoRequestHandler(nullptr /* connector */,
|
||||
protocols,
|
||||
std::move(callback)) {}
|
||||
~FakeFidoRequestHandler() override = default;
|
||||
|
||||
void DispatchRequest(FidoAuthenticator* authenticator) override {
|
||||
|
@ -7,25 +7,34 @@
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/bind_helpers.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/scoped_task_environment.h"
|
||||
#include "build/build_config.h"
|
||||
#include "device/base/features.h"
|
||||
#include "device/bluetooth/bluetooth_adapter_factory.h"
|
||||
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
|
||||
#include "device/fido/authenticator_get_assertion_response.h"
|
||||
#include "device/fido/buildflags.h"
|
||||
#include "device/fido/ctap_get_assertion_request.h"
|
||||
#include "device/fido/device_response_converter.h"
|
||||
#include "device/fido/fake_fido_discovery.h"
|
||||
#include "device/fido/features.h"
|
||||
#include "device/fido/fido_constants.h"
|
||||
#include "device/fido/fido_parsing_utils.h"
|
||||
#include "device/fido/fido_test_data.h"
|
||||
#include "device/fido/fido_transport_protocol.h"
|
||||
#include "device/fido/get_assertion_request_handler.h"
|
||||
#include "device/fido/hid/fake_hid_impl_for_testing.h"
|
||||
#include "device/fido/mock_fido_device.h"
|
||||
#include "device/fido/test_callback_receiver.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#if defined(OS_WIN) && BUILDFLAG(USE_WIN_WEBAUTHN_API)
|
||||
#include "device/fido/win/fake_webauthn_api.h"
|
||||
#endif
|
||||
|
||||
namespace device {
|
||||
|
||||
namespace {
|
||||
@ -711,4 +720,63 @@ TEST_F(FidoGetAssertionHandlerTest,
|
||||
get_assertion_callback().status());
|
||||
}
|
||||
|
||||
#if defined(OS_WIN) && BUILDFLAG(USE_WIN_WEBAUTHN_API)
|
||||
class GetAssertionRequestHandlerWinTest : public ::testing::Test {
|
||||
protected:
|
||||
base::test::ScopedTaskEnvironment scoped_task_environment_;
|
||||
ScopedFakeWinWebAuthnApi scoped_fake_win_webauthn_api_;
|
||||
};
|
||||
|
||||
// Verify that the request handler instantiates a HID device backed
|
||||
// FidoDeviceAuthenticator or a WinNativeCrossPlatformAuthenticator, depending
|
||||
// on feature flag and API availability.
|
||||
TEST_F(GetAssertionRequestHandlerWinTest, TestWinUsbDiscovery) {
|
||||
enum class DeviceType {
|
||||
kHid,
|
||||
kWinNative,
|
||||
};
|
||||
const struct TestCase {
|
||||
bool enable_win_webauthn_api;
|
||||
bool enable_feature_flag;
|
||||
DeviceType expect_device_type;
|
||||
} test_cases[] = {
|
||||
{false, false, DeviceType::kHid},
|
||||
{false, true, DeviceType::kHid},
|
||||
{true, false, DeviceType::kHid},
|
||||
{true, true, DeviceType::kWinNative},
|
||||
};
|
||||
size_t i = 0;
|
||||
for (const auto& test : test_cases) {
|
||||
SCOPED_TRACE(i++);
|
||||
scoped_fake_win_webauthn_api_.set_available(test.enable_win_webauthn_api);
|
||||
base::test::ScopedFeatureList scoped_feature_list;
|
||||
// Feature is default off (even with API present).
|
||||
if (test.enable_feature_flag)
|
||||
scoped_feature_list.InitAndEnableFeature(kWebAuthUseNativeWinApi);
|
||||
|
||||
TestGetAssertionRequestCallback cb;
|
||||
ScopedFakeHidManager fake_hid_manager_;
|
||||
auto handler = std::make_unique<GetAssertionRequestHandler>(
|
||||
fake_hid_manager_.service_manager_connector(),
|
||||
base::flat_set<FidoTransportProtocol>(
|
||||
{FidoTransportProtocol::kUsbHumanInterfaceDevice}),
|
||||
CtapGetAssertionRequest(test_data::kRelyingPartyId,
|
||||
test_data::kClientDataJson),
|
||||
|
||||
cb.callback());
|
||||
scoped_task_environment_.RunUntilIdle();
|
||||
|
||||
fake_hid_manager_.AddFidoHidDevice("guid");
|
||||
scoped_task_environment_.RunUntilIdle();
|
||||
|
||||
EXPECT_EQ(1u, handler->AuthenticatorsForTesting().size());
|
||||
// Crudely distinguish authenticator type by FidoAuthenticator::GetId.
|
||||
EXPECT_EQ(test.expect_device_type == DeviceType::kHid
|
||||
? "hid:guid"
|
||||
: "WinNativeCrossPlatformAuthenticator",
|
||||
handler->AuthenticatorsForTesting().begin()->second->GetId());
|
||||
}
|
||||
}
|
||||
#endif // defined(OS_WIN) && BUILDFLAG(USE_WIN_WEBAUTHN_API)
|
||||
|
||||
} // namespace device
|
||||
|
@ -7,6 +7,10 @@
|
||||
#include <utility>
|
||||
|
||||
#include "device/fido/fido_parsing_utils.h"
|
||||
#include "services/device/public/mojom/constants.mojom.h"
|
||||
#include "services/device/public/mojom/hid.mojom.h"
|
||||
#include "services/service_manager/public/cpp/connector.h"
|
||||
#include "services/service_manager/public/mojom/connector.mojom.h"
|
||||
|
||||
namespace device {
|
||||
|
||||
@ -126,6 +130,20 @@ void FakeHidManager::AddBinding2(device::mojom::HidManagerRequest request) {
|
||||
bindings_.AddBinding(this, std::move(request));
|
||||
}
|
||||
|
||||
void FakeHidManager::AddFidoHidDevice(std::string guid) {
|
||||
auto c_info = device::mojom::HidCollectionInfo::New();
|
||||
c_info->usage = device::mojom::HidUsageAndPage::New(1, 0xf1d0);
|
||||
auto device = device::mojom::HidDeviceInfo::New();
|
||||
device->guid = std::move(guid);
|
||||
device->product_name = "Test Fido Device";
|
||||
device->serial_number = "123FIDO";
|
||||
device->bus_type = device::mojom::HidBusType::kHIDBusTypeUSB;
|
||||
device->collections.push_back(std::move(c_info));
|
||||
device->max_input_report_size = 64;
|
||||
device->max_output_report_size = 64;
|
||||
AddDevice(std::move(device));
|
||||
}
|
||||
|
||||
void FakeHidManager::GetDevicesAndSetClient(
|
||||
device::mojom::HidManagerClientAssociatedPtrInfo client,
|
||||
GetDevicesCallback callback) {
|
||||
@ -184,4 +202,16 @@ void FakeHidManager::RemoveDevice(const std::string device_guid) {
|
||||
devices_.erase(it);
|
||||
}
|
||||
|
||||
ScopedFakeHidManager::ScopedFakeHidManager() {
|
||||
service_manager::mojom::ConnectorRequest request;
|
||||
connector_ = service_manager::Connector::Create(&request);
|
||||
service_manager::Connector::TestApi test_api(connector_.get());
|
||||
test_api.OverrideBinderForTesting(
|
||||
service_manager::Identity(device::mojom::kServiceName),
|
||||
device::mojom::HidManager::Name_,
|
||||
base::BindRepeating(&FakeHidManager::AddBinding, base::Unretained(this)));
|
||||
}
|
||||
|
||||
ScopedFakeHidManager::~ScopedFakeHidManager() = default;
|
||||
|
||||
} // namespace device
|
||||
|
@ -20,6 +20,10 @@
|
||||
#include "services/device/public/mojom/hid.mojom.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
|
||||
namespace service_manager {
|
||||
class Connector;
|
||||
}
|
||||
|
||||
namespace device {
|
||||
|
||||
class MockHidConnection : public device::mojom::HidConnection {
|
||||
@ -95,6 +99,9 @@ class FakeHidManager : public device::mojom::HidManager {
|
||||
FakeHidManager();
|
||||
~FakeHidManager() override;
|
||||
|
||||
// Invoke AddDevice with a device info struct that mirrors a FIDO USB device.
|
||||
void AddFidoHidDevice(std::string guid);
|
||||
|
||||
// device::mojom::HidManager implementation:
|
||||
void GetDevicesAndSetClient(
|
||||
device::mojom::HidManagerClientAssociatedPtrInfo client,
|
||||
@ -118,6 +125,23 @@ class FakeHidManager : public device::mojom::HidManager {
|
||||
DISALLOW_COPY_AND_ASSIGN(FakeHidManager);
|
||||
};
|
||||
|
||||
// ScopedFakeHidManager automatically binds itself to the device service for the
|
||||
// duration of its lifetime.
|
||||
class ScopedFakeHidManager : public FakeHidManager {
|
||||
public:
|
||||
ScopedFakeHidManager();
|
||||
~ScopedFakeHidManager() override;
|
||||
|
||||
service_manager::Connector* service_manager_connector() {
|
||||
return connector_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<service_manager::Connector> connector_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedFakeHidManager);
|
||||
};
|
||||
|
||||
} // namespace device
|
||||
|
||||
#endif // DEVICE_FIDO_HID_FAKE_HID_IMPL_FOR_TESTING_H_
|
||||
|
@ -25,21 +25,6 @@ using ::testing::_;
|
||||
|
||||
namespace {
|
||||
|
||||
device::mojom::HidDeviceInfoPtr MakeFidoHidDevice(std::string guid) {
|
||||
auto c_info = device::mojom::HidCollectionInfo::New();
|
||||
c_info->usage = device::mojom::HidUsageAndPage::New(1, 0xf1d0);
|
||||
|
||||
auto u2f_device = device::mojom::HidDeviceInfo::New();
|
||||
u2f_device->guid = std::move(guid);
|
||||
u2f_device->product_name = "Test Fido Device";
|
||||
u2f_device->serial_number = "123FIDO";
|
||||
u2f_device->bus_type = device::mojom::HidBusType::kHIDBusTypeUSB;
|
||||
u2f_device->collections.push_back(std::move(c_info));
|
||||
u2f_device->max_input_report_size = 64;
|
||||
u2f_device->max_output_report_size = 64;
|
||||
return u2f_device;
|
||||
}
|
||||
|
||||
device::mojom::HidDeviceInfoPtr MakeOtherDevice(std::string guid) {
|
||||
auto other_device = device::mojom::HidDeviceInfo::New();
|
||||
other_device->guid = std::move(guid);
|
||||
@ -56,35 +41,16 @@ MATCHER_P(IdMatches, id, "") {
|
||||
} // namespace
|
||||
|
||||
class FidoHidDiscoveryTest : public ::testing::Test {
|
||||
public:
|
||||
base::test::ScopedTaskEnvironment& scoped_task_environment() {
|
||||
return scoped_task_environment_;
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
fake_hid_manager_ = std::make_unique<FakeHidManager>();
|
||||
|
||||
service_manager::mojom::ConnectorRequest request;
|
||||
connector_ = service_manager::Connector::Create(&request);
|
||||
service_manager::Connector::TestApi test_api(connector_.get());
|
||||
test_api.OverrideBinderForTesting(
|
||||
service_manager::Identity(device::mojom::kServiceName),
|
||||
device::mojom::HidManager::Name_,
|
||||
base::Bind(&FakeHidManager::AddBinding,
|
||||
base::Unretained(fake_hid_manager_.get())));
|
||||
}
|
||||
|
||||
protected:
|
||||
base::test::ScopedTaskEnvironment scoped_task_environment_;
|
||||
std::unique_ptr<service_manager::Connector> connector_;
|
||||
std::unique_ptr<FakeHidManager> fake_hid_manager_;
|
||||
ScopedFakeHidManager fake_hid_manager_;
|
||||
};
|
||||
|
||||
TEST_F(FidoHidDiscoveryTest, TestAddRemoveDevice) {
|
||||
FidoHidDiscovery discovery(connector_.get());
|
||||
FidoHidDiscovery discovery(fake_hid_manager_.service_manager_connector());
|
||||
MockFidoDiscoveryObserver observer;
|
||||
|
||||
fake_hid_manager_->AddDevice(MakeFidoHidDevice("known"));
|
||||
fake_hid_manager_.AddFidoHidDevice("known");
|
||||
|
||||
EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
|
||||
discovery.set_observer(&observer);
|
||||
@ -93,28 +59,28 @@ TEST_F(FidoHidDiscoveryTest, TestAddRemoveDevice) {
|
||||
// Devices initially known to the service before discovery started should be
|
||||
// reported as KNOWN.
|
||||
EXPECT_CALL(observer, AuthenticatorAdded(&discovery, IdMatches("known")));
|
||||
scoped_task_environment().RunUntilIdle();
|
||||
scoped_task_environment_.RunUntilIdle();
|
||||
|
||||
// Devices added during the discovery should be reported as ADDED.
|
||||
EXPECT_CALL(observer, AuthenticatorAdded(&discovery, IdMatches("added")));
|
||||
fake_hid_manager_->AddDevice(MakeFidoHidDevice("added"));
|
||||
scoped_task_environment().RunUntilIdle();
|
||||
fake_hid_manager_.AddFidoHidDevice("added");
|
||||
scoped_task_environment_.RunUntilIdle();
|
||||
|
||||
// Added non-U2F devices should not be reported at all.
|
||||
EXPECT_CALL(observer, AuthenticatorAdded(_, _)).Times(0);
|
||||
fake_hid_manager_->AddDevice(MakeOtherDevice("other"));
|
||||
fake_hid_manager_.AddDevice(MakeOtherDevice("other"));
|
||||
|
||||
// Removed non-U2F devices should not be reported at all.
|
||||
EXPECT_CALL(observer, AuthenticatorRemoved(_, _)).Times(0);
|
||||
fake_hid_manager_->RemoveDevice("other");
|
||||
scoped_task_environment().RunUntilIdle();
|
||||
fake_hid_manager_.RemoveDevice("other");
|
||||
scoped_task_environment_.RunUntilIdle();
|
||||
|
||||
// Removed U2F devices should be reported as REMOVED.
|
||||
EXPECT_CALL(observer, AuthenticatorRemoved(&discovery, IdMatches("known")));
|
||||
EXPECT_CALL(observer, AuthenticatorRemoved(&discovery, IdMatches("added")));
|
||||
fake_hid_manager_->RemoveDevice("known");
|
||||
fake_hid_manager_->RemoveDevice("added");
|
||||
scoped_task_environment().RunUntilIdle();
|
||||
fake_hid_manager_.RemoveDevice("known");
|
||||
fake_hid_manager_.RemoveDevice("added");
|
||||
scoped_task_environment_.RunUntilIdle();
|
||||
}
|
||||
|
||||
} // namespace device
|
||||
|
@ -18,6 +18,7 @@ WinNativeCrossPlatformAuthenticatorDiscovery::
|
||||
~WinNativeCrossPlatformAuthenticatorDiscovery() = default;
|
||||
|
||||
void WinNativeCrossPlatformAuthenticatorDiscovery::Start() {
|
||||
DCHECK(!authenticator_);
|
||||
if (!observer()) {
|
||||
return;
|
||||
}
|
||||
|
@ -16,7 +16,8 @@ namespace device {
|
||||
|
||||
// Instantiates the authenticator subclass for forwarding requests to external
|
||||
// authenticators via the Windows WebAuthn API.
|
||||
class WinNativeCrossPlatformAuthenticatorDiscovery : public FidoDiscoveryBase {
|
||||
class COMPONENT_EXPORT(DEVICE_FIDO) WinNativeCrossPlatformAuthenticatorDiscovery
|
||||
: public FidoDiscoveryBase {
|
||||
public:
|
||||
WinNativeCrossPlatformAuthenticatorDiscovery(
|
||||
WinWebAuthnApi* const win_webauthn_api,
|
||||
|
65
device/fido/win/fake_webauthn_api.cc
Normal file
65
device/fido/win/fake_webauthn_api.cc
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2018 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 "device/fido/win/fake_webauthn_api.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace device {
|
||||
|
||||
FakeWinWebAuthnApi::FakeWinWebAuthnApi() = default;
|
||||
FakeWinWebAuthnApi::~FakeWinWebAuthnApi() = default;
|
||||
|
||||
bool FakeWinWebAuthnApi::IsAvailable() const {
|
||||
return is_available_;
|
||||
}
|
||||
|
||||
HRESULT FakeWinWebAuthnApi::IsUserVerifyingPlatformAuthenticatorAvailable(
|
||||
BOOL* result) {
|
||||
*result = false;
|
||||
DCHECK(is_available_);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT FakeWinWebAuthnApi::AuthenticatorMakeCredential(
|
||||
HWND h_wnd,
|
||||
const WEBAUTHN_RP_ENTITY_INFORMATION* rp_information,
|
||||
const WEBAUTHN_USER_ENTITY_INFORMATION* user_information,
|
||||
const WEBAUTHN_COSE_CREDENTIAL_PARAMETERS* pub_key_cred_params,
|
||||
const WEBAUTHN_CLIENT_DATA* client_data,
|
||||
const WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS* options,
|
||||
ScopedCredentialAttestation* credential_attestation) {
|
||||
DCHECK(is_available_);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT FakeWinWebAuthnApi::AuthenticatorGetAssertion(
|
||||
HWND h_wnd,
|
||||
const wchar_t* rp_id_utf16,
|
||||
const WEBAUTHN_CLIENT_DATA* client_data,
|
||||
const WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS* options,
|
||||
ScopedAssertion* assertion) {
|
||||
DCHECK(is_available_);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT FakeWinWebAuthnApi::CancelCurrentOperation(GUID* cancellation_id) {
|
||||
DCHECK(is_available_);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
const wchar_t* FakeWinWebAuthnApi::GetErrorName(HRESULT hr) {
|
||||
DCHECK(is_available_);
|
||||
return L"not implemented";
|
||||
};
|
||||
|
||||
ScopedFakeWinWebAuthnApi::ScopedFakeWinWebAuthnApi() : FakeWinWebAuthnApi() {
|
||||
WinWebAuthnApi::SetDefaultForTesting(this);
|
||||
}
|
||||
|
||||
ScopedFakeWinWebAuthnApi::~ScopedFakeWinWebAuthnApi() {
|
||||
WinWebAuthnApi::ClearDefaultForTesting();
|
||||
}
|
||||
|
||||
} // namespace device
|
58
device/fido/win/fake_webauthn_api.h
Normal file
58
device/fido/win/fake_webauthn_api.h
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
#ifndef DEVICE_FIDO_WIN_FAKE_WEBAUTHN_API_H_
|
||||
#define DEVICE_FIDO_WIN_FAKE_WEBAUTHN_API_H_
|
||||
#include "base/macros.h"
|
||||
#include "device/fido/win/webauthn_api.h"
|
||||
|
||||
namespace device {
|
||||
|
||||
class FakeWinWebAuthnApi : public WinWebAuthnApi {
|
||||
public:
|
||||
FakeWinWebAuthnApi();
|
||||
~FakeWinWebAuthnApi() override;
|
||||
|
||||
// Inject the return value for WinWebAuthnApi::IsAvailable().
|
||||
void set_available(bool available) { is_available_ = available; }
|
||||
|
||||
// WinWebAuthnApi:
|
||||
bool IsAvailable() const override;
|
||||
// The following methods all return E_NOTIMPL immediately.
|
||||
HRESULT IsUserVerifyingPlatformAuthenticatorAvailable(
|
||||
BOOL* available) override;
|
||||
HRESULT AuthenticatorMakeCredential(
|
||||
HWND h_wnd,
|
||||
const WEBAUTHN_RP_ENTITY_INFORMATION* rp_information,
|
||||
const WEBAUTHN_USER_ENTITY_INFORMATION* user_information,
|
||||
const WEBAUTHN_COSE_CREDENTIAL_PARAMETERS* pub_key_cred_params,
|
||||
const WEBAUTHN_CLIENT_DATA* client_data,
|
||||
const WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS* options,
|
||||
ScopedCredentialAttestation* credential_attestation) override;
|
||||
HRESULT AuthenticatorGetAssertion(
|
||||
HWND h_wnd,
|
||||
const wchar_t* rp_id_utf16,
|
||||
const WEBAUTHN_CLIENT_DATA* client_data,
|
||||
const WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS* options,
|
||||
ScopedAssertion* assertion) override;
|
||||
HRESULT CancelCurrentOperation(GUID* cancellation_id) override;
|
||||
// Returns L"not implemented".
|
||||
const wchar_t* GetErrorName(HRESULT hr) override;
|
||||
|
||||
private:
|
||||
bool is_available_ = true;
|
||||
};
|
||||
|
||||
// ScopedFakeWinWebAuthnApi overrides the value returned
|
||||
// by WinWebAuthnApi::GetDefault with itself for the duration of its
|
||||
// lifetime.
|
||||
class ScopedFakeWinWebAuthnApi : public FakeWinWebAuthnApi {
|
||||
public:
|
||||
ScopedFakeWinWebAuthnApi();
|
||||
~ScopedFakeWinWebAuthnApi() override;
|
||||
};
|
||||
|
||||
} // namespace device
|
||||
|
||||
#endif // DEVICE_FIDO_WIN_FAKE_WEBAUTHN_API_H_
|
@ -116,12 +116,30 @@ class WinWebAuthnApiImpl : public WinWebAuthnApi {
|
||||
bool is_bound_ = false;
|
||||
};
|
||||
|
||||
static WinWebAuthnApi* kDefaultForTesting = nullptr;
|
||||
|
||||
// static
|
||||
WinWebAuthnApi* WinWebAuthnApi::GetDefault() {
|
||||
if (kDefaultForTesting) {
|
||||
return kDefaultForTesting;
|
||||
}
|
||||
|
||||
static base::NoDestructor<WinWebAuthnApiImpl> api;
|
||||
return api.get();
|
||||
}
|
||||
|
||||
// static
|
||||
void WinWebAuthnApi::SetDefaultForTesting(WinWebAuthnApi* api) {
|
||||
DCHECK(!kDefaultForTesting);
|
||||
kDefaultForTesting = api;
|
||||
}
|
||||
|
||||
// static
|
||||
void WinWebAuthnApi::ClearDefaultForTesting() {
|
||||
DCHECK(kDefaultForTesting);
|
||||
kDefaultForTesting = nullptr;
|
||||
}
|
||||
|
||||
WinWebAuthnApi::~WinWebAuthnApi() = default;
|
||||
|
||||
} // namespace device
|
||||
|
@ -21,9 +21,6 @@ namespace device {
|
||||
// Users must check the result of |IsAvailable| on the instance to verify that
|
||||
// the native library was loaded successfully before invoking any of the other
|
||||
// methods.
|
||||
//
|
||||
// TODO(martinkr): Add a ScopedFakeWinWebAuthnApi that overrides
|
||||
// |GetDefault| for testing.
|
||||
class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApi {
|
||||
public:
|
||||
// ScopedCredentialAttestation is a scoped deleter for a
|
||||
@ -84,6 +81,11 @@ class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApi {
|
||||
|
||||
// See WebAuthNGetErrorName in <webauthn.h>.
|
||||
virtual const wchar_t* GetErrorName(HRESULT hr) = 0;
|
||||
|
||||
private:
|
||||
friend class ScopedFakeWinWebAuthnApi;
|
||||
static void SetDefaultForTesting(WinWebAuthnApi* api);
|
||||
static void ClearDefaultForTesting();
|
||||
};
|
||||
|
||||
} // namespace device
|
||||
|
Reference in New Issue
Block a user