Commit df06312d authored by Martin Kreichgauer's avatar Martin Kreichgauer Committed by Commit Bot

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: default avatarJun Choi <hongjunchoi@chromium.org>
Reviewed-by: default avatarAdam Langley <agl@chromium.org>
Cr-Commit-Position: refs/heads/master@{#606254}
parent aa8e030a
...@@ -143,7 +143,6 @@ component("fido") { ...@@ -143,7 +143,6 @@ component("fido") {
defines = [ "IS_DEVICE_FIDO_IMPL" ] defines = [ "IS_DEVICE_FIDO_IMPL" ]
deps = [ deps = [
":buildflags",
"//components/apdu", "//components/apdu",
"//components/cbor", "//components/cbor",
"//crypto", "//crypto",
...@@ -156,6 +155,7 @@ component("fido") { ...@@ -156,6 +155,7 @@ component("fido") {
] ]
public_deps = [ public_deps = [
":buildflags",
"//base", "//base",
"//device/bluetooth", "//device/bluetooth",
"//services/device/public/mojom", "//services/device/public/mojom",
...@@ -307,6 +307,8 @@ source_set("test_support") { ...@@ -307,6 +307,8 @@ source_set("test_support") {
"//device/fido", "//device/fido",
"//mojo/public/cpp/bindings", "//mojo/public/cpp/bindings",
"//services/device/public/mojom", "//services/device/public/mojom",
"//services/service_manager/public/cpp",
"//services/service_manager/public/mojom",
"//testing/gmock", "//testing/gmock",
"//testing/gtest", "//testing/gtest",
] ]
...@@ -329,4 +331,11 @@ source_set("test_support") { ...@@ -329,4 +331,11 @@ source_set("test_support") {
"mac/scoped_touch_id_test_environment.mm", "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 ...@@ -180,6 +180,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
return transport_availability_info_; return transport_availability_info_;
} }
const AuthenticatorMap& AuthenticatorsForTesting() {
return active_authenticators_;
}
protected: protected:
// Subclasses implement this method to dispatch their request onto the given // Subclasses implement this method to dispatch their request onto the given
// FidoAuthenticator. The FidoAuthenticator is owned by this // FidoAuthenticator. The FidoAuthenticator is owned by this
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "device/bluetooth/bluetooth_adapter_factory.h" #include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h" #include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/fido/buildflags.h"
#include "device/fido/fake_fido_discovery.h" #include "device/fido/fake_fido_discovery.h"
#include "device/fido/fido_constants.h" #include "device/fido/fido_constants.h"
#include "device/fido/fido_device.h" #include "device/fido/fido_device.h"
...@@ -174,14 +175,18 @@ class FakeFidoAuthenticator : public FidoDeviceAuthenticator { ...@@ -174,14 +175,18 @@ class FakeFidoAuthenticator : public FidoDeviceAuthenticator {
class FakeFidoRequestHandler : public FidoRequestHandler<std::vector<uint8_t>> { class FakeFidoRequestHandler : public FidoRequestHandler<std::vector<uint8_t>> {
public: public:
FakeFidoRequestHandler(const base::flat_set<FidoTransportProtocol>& protocols, FakeFidoRequestHandler(service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& protocols,
FakeHandlerCallback callback) FakeHandlerCallback callback)
: FidoRequestHandler(nullptr /* connector */, : FidoRequestHandler(connector, protocols, std::move(callback)),
protocols,
std::move(callback)),
weak_factory_(this) { weak_factory_(this) {
Start(); Start();
} }
FakeFidoRequestHandler(const base::flat_set<FidoTransportProtocol>& protocols,
FakeHandlerCallback callback)
: FakeFidoRequestHandler(nullptr /* connector */,
protocols,
std::move(callback)) {}
~FakeFidoRequestHandler() override = default; ~FakeFidoRequestHandler() override = default;
void DispatchRequest(FidoAuthenticator* authenticator) override { void DispatchRequest(FidoAuthenticator* authenticator) override {
......
...@@ -7,25 +7,34 @@ ...@@ -7,25 +7,34 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/stl_util.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
#include "device/base/features.h" #include "device/base/features.h"
#include "device/bluetooth/bluetooth_adapter_factory.h" #include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h" #include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/fido/authenticator_get_assertion_response.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/ctap_get_assertion_request.h"
#include "device/fido/device_response_converter.h" #include "device/fido/device_response_converter.h"
#include "device/fido/fake_fido_discovery.h" #include "device/fido/fake_fido_discovery.h"
#include "device/fido/features.h"
#include "device/fido/fido_constants.h" #include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h" #include "device/fido/fido_parsing_utils.h"
#include "device/fido/fido_test_data.h" #include "device/fido/fido_test_data.h"
#include "device/fido/fido_transport_protocol.h" #include "device/fido/fido_transport_protocol.h"
#include "device/fido/get_assertion_request_handler.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/mock_fido_device.h"
#include "device/fido/test_callback_receiver.h" #include "device/fido/test_callback_receiver.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.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 device {
namespace { namespace {
...@@ -711,4 +720,63 @@ TEST_F(FidoGetAssertionHandlerTest, ...@@ -711,4 +720,63 @@ TEST_F(FidoGetAssertionHandlerTest,
get_assertion_callback().status()); 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 } // namespace device
...@@ -7,6 +7,10 @@ ...@@ -7,6 +7,10 @@
#include <utility> #include <utility>
#include "device/fido/fido_parsing_utils.h" #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 { namespace device {
...@@ -126,6 +130,20 @@ void FakeHidManager::AddBinding2(device::mojom::HidManagerRequest request) { ...@@ -126,6 +130,20 @@ void FakeHidManager::AddBinding2(device::mojom::HidManagerRequest request) {
bindings_.AddBinding(this, std::move(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( void FakeHidManager::GetDevicesAndSetClient(
device::mojom::HidManagerClientAssociatedPtrInfo client, device::mojom::HidManagerClientAssociatedPtrInfo client,
GetDevicesCallback callback) { GetDevicesCallback callback) {
...@@ -184,4 +202,16 @@ void FakeHidManager::RemoveDevice(const std::string device_guid) { ...@@ -184,4 +202,16 @@ void FakeHidManager::RemoveDevice(const std::string device_guid) {
devices_.erase(it); 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 } // namespace device
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
#include "services/device/public/mojom/hid.mojom.h" #include "services/device/public/mojom/hid.mojom.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
namespace service_manager {
class Connector;
}
namespace device { namespace device {
class MockHidConnection : public device::mojom::HidConnection { class MockHidConnection : public device::mojom::HidConnection {
...@@ -95,6 +99,9 @@ class FakeHidManager : public device::mojom::HidManager { ...@@ -95,6 +99,9 @@ class FakeHidManager : public device::mojom::HidManager {
FakeHidManager(); FakeHidManager();
~FakeHidManager() override; ~FakeHidManager() override;
// Invoke AddDevice with a device info struct that mirrors a FIDO USB device.
void AddFidoHidDevice(std::string guid);
// device::mojom::HidManager implementation: // device::mojom::HidManager implementation:
void GetDevicesAndSetClient( void GetDevicesAndSetClient(
device::mojom::HidManagerClientAssociatedPtrInfo client, device::mojom::HidManagerClientAssociatedPtrInfo client,
...@@ -118,6 +125,23 @@ class FakeHidManager : public device::mojom::HidManager { ...@@ -118,6 +125,23 @@ class FakeHidManager : public device::mojom::HidManager {
DISALLOW_COPY_AND_ASSIGN(FakeHidManager); 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 } // namespace device
#endif // DEVICE_FIDO_HID_FAKE_HID_IMPL_FOR_TESTING_H_ #endif // DEVICE_FIDO_HID_FAKE_HID_IMPL_FOR_TESTING_H_
...@@ -25,21 +25,6 @@ using ::testing::_; ...@@ -25,21 +25,6 @@ using ::testing::_;
namespace { 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) { device::mojom::HidDeviceInfoPtr MakeOtherDevice(std::string guid) {
auto other_device = device::mojom::HidDeviceInfo::New(); auto other_device = device::mojom::HidDeviceInfo::New();
other_device->guid = std::move(guid); other_device->guid = std::move(guid);
...@@ -56,35 +41,16 @@ MATCHER_P(IdMatches, id, "") { ...@@ -56,35 +41,16 @@ MATCHER_P(IdMatches, id, "") {
} // namespace } // namespace
class FidoHidDiscoveryTest : public ::testing::Test { 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: protected:
base::test::ScopedTaskEnvironment scoped_task_environment_; base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<service_manager::Connector> connector_; ScopedFakeHidManager fake_hid_manager_;
std::unique_ptr<FakeHidManager> fake_hid_manager_;
}; };
TEST_F(FidoHidDiscoveryTest, TestAddRemoveDevice) { TEST_F(FidoHidDiscoveryTest, TestAddRemoveDevice) {
FidoHidDiscovery discovery(connector_.get()); FidoHidDiscovery discovery(fake_hid_manager_.service_manager_connector());
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
fake_hid_manager_->AddDevice(MakeFidoHidDevice("known")); fake_hid_manager_.AddFidoHidDevice("known");
EXPECT_CALL(observer, DiscoveryStarted(&discovery, true)); EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
discovery.set_observer(&observer); discovery.set_observer(&observer);
...@@ -93,28 +59,28 @@ TEST_F(FidoHidDiscoveryTest, TestAddRemoveDevice) { ...@@ -93,28 +59,28 @@ TEST_F(FidoHidDiscoveryTest, TestAddRemoveDevice) {
// Devices initially known to the service before discovery started should be // Devices initially known to the service before discovery started should be
// reported as KNOWN. // reported as KNOWN.
EXPECT_CALL(observer, AuthenticatorAdded(&discovery, IdMatches("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. // Devices added during the discovery should be reported as ADDED.
EXPECT_CALL(observer, AuthenticatorAdded(&discovery, IdMatches("added"))); EXPECT_CALL(observer, AuthenticatorAdded(&discovery, IdMatches("added")));
fake_hid_manager_->AddDevice(MakeFidoHidDevice("added")); fake_hid_manager_.AddFidoHidDevice("added");
scoped_task_environment().RunUntilIdle(); scoped_task_environment_.RunUntilIdle();
// Added non-U2F devices should not be reported at all. // Added non-U2F devices should not be reported at all.
EXPECT_CALL(observer, AuthenticatorAdded(_, _)).Times(0); 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. // Removed non-U2F devices should not be reported at all.
EXPECT_CALL(observer, AuthenticatorRemoved(_, _)).Times(0); EXPECT_CALL(observer, AuthenticatorRemoved(_, _)).Times(0);
fake_hid_manager_->RemoveDevice("other"); fake_hid_manager_.RemoveDevice("other");
scoped_task_environment().RunUntilIdle(); scoped_task_environment_.RunUntilIdle();
// Removed U2F devices should be reported as REMOVED. // Removed U2F devices should be reported as REMOVED.
EXPECT_CALL(observer, AuthenticatorRemoved(&discovery, IdMatches("known"))); EXPECT_CALL(observer, AuthenticatorRemoved(&discovery, IdMatches("known")));
EXPECT_CALL(observer, AuthenticatorRemoved(&discovery, IdMatches("added"))); EXPECT_CALL(observer, AuthenticatorRemoved(&discovery, IdMatches("added")));
fake_hid_manager_->RemoveDevice("known"); fake_hid_manager_.RemoveDevice("known");
fake_hid_manager_->RemoveDevice("added"); fake_hid_manager_.RemoveDevice("added");
scoped_task_environment().RunUntilIdle(); scoped_task_environment_.RunUntilIdle();
} }
} // namespace device } // namespace device
...@@ -18,6 +18,7 @@ WinNativeCrossPlatformAuthenticatorDiscovery:: ...@@ -18,6 +18,7 @@ WinNativeCrossPlatformAuthenticatorDiscovery::
~WinNativeCrossPlatformAuthenticatorDiscovery() = default; ~WinNativeCrossPlatformAuthenticatorDiscovery() = default;
void WinNativeCrossPlatformAuthenticatorDiscovery::Start() { void WinNativeCrossPlatformAuthenticatorDiscovery::Start() {
DCHECK(!authenticator_);
if (!observer()) { if (!observer()) {
return; return;
} }
......
...@@ -16,7 +16,8 @@ namespace device { ...@@ -16,7 +16,8 @@ namespace device {
// Instantiates the authenticator subclass for forwarding requests to external // Instantiates the authenticator subclass for forwarding requests to external
// authenticators via the Windows WebAuthn API. // authenticators via the Windows WebAuthn API.
class WinNativeCrossPlatformAuthenticatorDiscovery : public FidoDiscoveryBase { class COMPONENT_EXPORT(DEVICE_FIDO) WinNativeCrossPlatformAuthenticatorDiscovery
: public FidoDiscoveryBase {
public: public:
WinNativeCrossPlatformAuthenticatorDiscovery( WinNativeCrossPlatformAuthenticatorDiscovery(
WinWebAuthnApi* const win_webauthn_api, WinWebAuthnApi* const win_webauthn_api,
......
// 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
// 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 { ...@@ -116,12 +116,30 @@ class WinWebAuthnApiImpl : public WinWebAuthnApi {
bool is_bound_ = false; bool is_bound_ = false;
}; };
static WinWebAuthnApi* kDefaultForTesting = nullptr;
// static // static
WinWebAuthnApi* WinWebAuthnApi::GetDefault() { WinWebAuthnApi* WinWebAuthnApi::GetDefault() {
if (kDefaultForTesting) {
return kDefaultForTesting;
}
static base::NoDestructor<WinWebAuthnApiImpl> api; static base::NoDestructor<WinWebAuthnApiImpl> api;
return api.get(); return api.get();
} }
// static
void WinWebAuthnApi::SetDefaultForTesting(WinWebAuthnApi* api) {
DCHECK(!kDefaultForTesting);
kDefaultForTesting = api;
}
// static
void WinWebAuthnApi::ClearDefaultForTesting() {
DCHECK(kDefaultForTesting);
kDefaultForTesting = nullptr;
}
WinWebAuthnApi::~WinWebAuthnApi() = default; WinWebAuthnApi::~WinWebAuthnApi() = default;
} // namespace device } // namespace device
...@@ -21,9 +21,6 @@ namespace device { ...@@ -21,9 +21,6 @@ namespace device {
// Users must check the result of |IsAvailable| on the instance to verify that // 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 // the native library was loaded successfully before invoking any of the other
// methods. // methods.
//
// TODO(martinkr): Add a ScopedFakeWinWebAuthnApi that overrides
// |GetDefault| for testing.
class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApi { class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApi {
public: public:
// ScopedCredentialAttestation is a scoped deleter for a // ScopedCredentialAttestation is a scoped deleter for a
...@@ -84,6 +81,11 @@ class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApi { ...@@ -84,6 +81,11 @@ class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApi {
// See WebAuthNGetErrorName in <webauthn.h>. // See WebAuthNGetErrorName in <webauthn.h>.
virtual const wchar_t* GetErrorName(HRESULT hr) = 0; virtual const wchar_t* GetErrorName(HRESULT hr) = 0;
private:
friend class ScopedFakeWinWebAuthnApi;
static void SetDefaultForTesting(WinWebAuthnApi* api);
static void ClearDefaultForTesting();
}; };
} // namespace device } // namespace device
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment