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

fido: invoke Windows API authenticator for all transports

Rather than only forwarding USB requests to the Windows WebAuthn API,
we are going to forward all requests. This consequently renames the
FidoAuthenticator subclass to WinWebAuthnApiAuthenticator. The
corresponding FidoDiscovery is instantiated for all requests where the
WebAuthn API is available (i.e., the feature is flag enabled, and the
DLL can be loaded and is at least version 1). When it is indeed
available, all other discoveries are disabled and the UI is suppressed
via a newly introduced option in the TransportAvailabilityInfo struct
relayed to embedders via the TransportAvailabilityObserver interface.

Note this temporarily breaks caBLE whenever the Windows API is
flag-enabled and available. (But the OS would presumably block the
device communication in that case anyway.)

Bug: 898718
Change-Id: If2bddac4bac519d1aa5aa9cb5d8fdc326297de73
Reviewed-on: https://chromium-review.googlesource.com/c/1330897
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@{#608127}
parent 0449c728
...@@ -88,6 +88,7 @@ void AuthenticatorRequestDialogModel::StartFlow( ...@@ -88,6 +88,7 @@ void AuthenticatorRequestDialogModel::StartFlow(
TransportAvailabilityInfo transport_availability, TransportAvailabilityInfo transport_availability,
base::Optional<device::FidoTransportProtocol> last_used_transport) { base::Optional<device::FidoTransportProtocol> last_used_transport) {
DCHECK_EQ(current_step(), Step::kNotStarted); DCHECK_EQ(current_step(), Step::kNotStarted);
DCHECK(!transport_availability.disable_embedder_ui);
transport_availability_ = std::move(transport_availability); transport_availability_ = std::move(transport_availability);
last_used_transport_ = last_used_transport; last_used_transport_ = last_used_transport;
......
...@@ -62,10 +62,6 @@ bool IsWebauthnRPIDListedInEnterprisePolicy( ...@@ -62,10 +62,6 @@ bool IsWebauthnRPIDListedInEnterprisePolicy(
#endif #endif
} }
bool IsWebAuthnUiEnabled() {
return base::FeatureList::IsEnabled(features::kWebAuthenticationUI);
}
} // namespace } // namespace
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
...@@ -267,6 +263,11 @@ void ChromeAuthenticatorRequestDelegate::UpdateLastTransportUsed( ...@@ -267,6 +263,11 @@ void ChromeAuthenticatorRequestDelegate::UpdateLastTransportUsed(
void ChromeAuthenticatorRequestDelegate::OnTransportAvailabilityEnumerated( void ChromeAuthenticatorRequestDelegate::OnTransportAvailabilityEnumerated(
device::FidoRequestHandlerBase::TransportAvailabilityInfo data) { device::FidoRequestHandlerBase::TransportAvailabilityInfo data) {
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
if (data.disable_embedder_ui) {
disable_ui_ = true;
return;
}
if (!IsWebAuthnUiEnabled()) if (!IsWebAuthnUiEnabled())
return; return;
...@@ -282,11 +283,14 @@ void ChromeAuthenticatorRequestDelegate::OnTransportAvailabilityEnumerated( ...@@ -282,11 +283,14 @@ void ChromeAuthenticatorRequestDelegate::OnTransportAvailabilityEnumerated(
bool ChromeAuthenticatorRequestDelegate::EmbedderControlsAuthenticatorDispatch( bool ChromeAuthenticatorRequestDelegate::EmbedderControlsAuthenticatorDispatch(
const device::FidoAuthenticator& authenticator) { const device::FidoAuthenticator& authenticator) {
// TODO(hongjunchoi): Change this so that requests for BLE authenticators are // TODO(hongjunchoi): Change this so that requests for BLE authenticators
// not dispatched immediately if WebAuthN UI is enabled. // are not dispatched immediately if WebAuthN UI is enabled.
if (!IsWebAuthnUiEnabled()) if (!IsWebAuthnUiEnabled())
return false; return false;
// On macOS, a native dialog is shown for the Touch ID authenticator
// immediately after dispatch to that authenticator. This dialog must not
// be triggered before Chrome's WebAuthn UI has advanced accordingly.
return authenticator.AuthenticatorTransport() && return authenticator.AuthenticatorTransport() &&
*authenticator.AuthenticatorTransport() == *authenticator.AuthenticatorTransport() ==
device::FidoTransportProtocol::kInternal; device::FidoTransportProtocol::kInternal;
...@@ -384,3 +388,10 @@ ChromeAuthenticatorRequestDelegate::GetPreviouslyPairedFidoBleDeviceAddresses() ...@@ -384,3 +388,10 @@ ChromeAuthenticatorRequestDelegate::GetPreviouslyPairedFidoBleDeviceAddresses()
Profile::FromBrowserContext(browser_context())->GetPrefs(); Profile::FromBrowserContext(browser_context())->GetPrefs();
return prefs->GetList(kWebAuthnBlePairedMacAddressesPrefName); return prefs->GetList(kWebAuthnBlePairedMacAddressesPrefName);
} }
bool ChromeAuthenticatorRequestDelegate::IsWebAuthnUiEnabled() const {
// UI can be disabled via flag or by the request handler for certain
// requests (e.g. on Windows, where the native API renders its own UI).
return base::FeatureList::IsEnabled(features::kWebAuthenticationUI) &&
!disable_ui_;
}
...@@ -106,6 +106,7 @@ class ChromeAuthenticatorRequestDelegate ...@@ -106,6 +106,7 @@ class ChromeAuthenticatorRequestDelegate
void AddFidoBleDeviceToPairedList(std::string device_address); void AddFidoBleDeviceToPairedList(std::string device_address);
base::Optional<device::FidoTransportProtocol> GetLastTransportUsed() const; base::Optional<device::FidoTransportProtocol> GetLastTransportUsed() const;
const base::ListValue* GetPreviouslyPairedFidoBleDeviceAddresses() const; const base::ListValue* GetPreviouslyPairedFidoBleDeviceAddresses() const;
bool IsWebAuthnUiEnabled() const;
content::RenderFrameHost* const render_frame_host_; content::RenderFrameHost* const render_frame_host_;
AuthenticatorRequestDialogModel* weak_dialog_model_ = nullptr; AuthenticatorRequestDialogModel* weak_dialog_model_ = nullptr;
...@@ -119,6 +120,11 @@ class ChromeAuthenticatorRequestDelegate ...@@ -119,6 +120,11 @@ class ChromeAuthenticatorRequestDelegate
base::OnceClosure cancel_callback_; base::OnceClosure cancel_callback_;
device::FidoRequestHandlerBase::RequestCallback request_callback_; device::FidoRequestHandlerBase::RequestCallback request_callback_;
// If in the TransportAvailabilityInfo reported by the request handler,
// disable_embedder_ui is set, this will be set to true. No UI must be
// rendered and all request handler callbacks will be ignored.
bool disable_ui_ = false;
base::WeakPtrFactory<ChromeAuthenticatorRequestDelegate> weak_ptr_factory_; base::WeakPtrFactory<ChromeAuthenticatorRequestDelegate> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ChromeAuthenticatorRequestDelegate); DISALLOW_COPY_AND_ASSIGN(ChromeAuthenticatorRequestDelegate);
......
...@@ -33,19 +33,6 @@ std::unique_ptr<FidoDiscoveryBase> CreateUsbFidoDiscovery( ...@@ -33,19 +33,6 @@ std::unique_ptr<FidoDiscoveryBase> CreateUsbFidoDiscovery(
return nullptr; return nullptr;
#else #else
#if defined(OS_WIN)
// On platforms where the Windows webauthn.dll is present, access to USB
// devices is blocked and we use a special authenticator that forwards
// requests to the Windows WebAuthn API instead.
if (base::FeatureList::IsEnabled(device::kWebAuthUseNativeWinApi) &&
WinWebAuthnApi::GetDefault()->IsAvailable()) {
return std::make_unique<WinNativeCrossPlatformAuthenticatorDiscovery>(
WinWebAuthnApi::GetDefault(),
// TODO(martinkr): Inject the window from which the request originated.
GetForegroundWindow());
}
#endif // defined(OS_WIN)
DCHECK(connector); DCHECK(connector);
return std::make_unique<FidoHidDiscovery>(connector); return std::make_unique<FidoHidDiscovery>(connector);
#endif // !defined(OS_ANDROID) #endif // !defined(OS_ANDROID)
...@@ -74,13 +61,13 @@ std::unique_ptr<FidoDiscoveryBase> CreateFidoDiscoveryImpl( ...@@ -74,13 +61,13 @@ std::unique_ptr<FidoDiscoveryBase> CreateFidoDiscoveryImpl(
return nullptr; return nullptr;
} }
} // namespace
std::unique_ptr<FidoDiscoveryBase> CreateCableDiscoveryImpl( std::unique_ptr<FidoDiscoveryBase> CreateCableDiscoveryImpl(
std::vector<CableDiscoveryData> cable_data) { std::vector<CableDiscoveryData> cable_data) {
return std::make_unique<FidoCableDiscovery>(std::move(cable_data)); return std::make_unique<FidoCableDiscovery>(std::move(cable_data));
} }
} // namespace
// static // static
FidoDiscoveryFactory::FactoryFuncPtr FidoDiscoveryFactory::g_factory_func_ = FidoDiscoveryFactory::FactoryFuncPtr FidoDiscoveryFactory::g_factory_func_ =
&CreateFidoDiscoveryImpl; &CreateFidoDiscoveryImpl;
...@@ -102,6 +89,26 @@ std::unique_ptr<FidoDiscoveryBase> FidoDiscoveryFactory::CreateCable( ...@@ -102,6 +89,26 @@ std::unique_ptr<FidoDiscoveryBase> FidoDiscoveryFactory::CreateCable(
return (*g_cable_factory_func_)(std::move(cable_data)); return (*g_cable_factory_func_)(std::move(cable_data));
} }
// static
#if defined(OS_WIN)
std::unique_ptr<FidoDiscoveryBase>
FidoDiscoveryFactory::MaybeCreateWinWebAuthnApiDiscovery() {
if (!base::FeatureList::IsEnabled(device::kWebAuthUseNativeWinApi) ||
!WinWebAuthnApi::GetDefault()->IsAvailable()) {
return nullptr;
}
return std::make_unique<WinWebAuthnApiAuthenticatorDiscovery>(
WinWebAuthnApi::GetDefault(),
// TODO(martinkr): Inject the window from which the request
// originated. Windows uses this parameter to center the
// dialog over the parent. The dialog should be centered
// over the originating Chrome Window; the foreground window
// may have changed to something else since the request was
// issued.
GetForegroundWindow());
}
#endif // defined(OS_WIN)
// ScopedFidoDiscoveryFactory ------------------------------------------------- // ScopedFidoDiscoveryFactory -------------------------------------------------
namespace internal { namespace internal {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "base/component_export.h" #include "base/component_export.h"
#include "build/build_config.h"
#include "device/fido/cable/cable_discovery_data.h" #include "device/fido/cable/cable_discovery_data.h"
#include "device/fido/fido_device_discovery.h" #include "device/fido/fido_device_discovery.h"
#include "device/fido/fido_discovery_base.h" #include "device/fido/fido_discovery_base.h"
...@@ -39,6 +40,12 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory { ...@@ -39,6 +40,12 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory {
// Instantiates a FidoDiscovery for caBLE. // Instantiates a FidoDiscovery for caBLE.
static std::unique_ptr<FidoDiscoveryBase> CreateCable( static std::unique_ptr<FidoDiscoveryBase> CreateCable(
std::vector<CableDiscoveryData> cable_data); std::vector<CableDiscoveryData> cable_data);
#if defined(OS_WIN)
// Instantiates a FidoDiscovery for the native Windows WebAuthn
// API where available. Returns nullptr otherwise.
static std::unique_ptr<FidoDiscoveryBase>
MaybeCreateWinWebAuthnApiDiscovery();
#endif // defined(OS_WIN)
private: private:
friend class internal::ScopedFidoDiscoveryFactory; friend class internal::ScopedFidoDiscoveryFactory;
......
...@@ -58,7 +58,16 @@ FidoRequestHandlerBase::TransportAvailabilityObserver:: ...@@ -58,7 +58,16 @@ FidoRequestHandlerBase::TransportAvailabilityObserver::
FidoRequestHandlerBase::FidoRequestHandlerBase( FidoRequestHandlerBase::FidoRequestHandlerBase(
service_manager::Connector* connector, service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& available_transports) const base::flat_set<FidoTransportProtocol>& available_transports)
: weak_factory_(this) { : connector_(connector), weak_factory_(this) {
#if defined(OS_WIN)
InitDiscoveriesWin(available_transports);
#else
InitDiscoveries(available_transports);
#endif // !defined(OS_WIN)
}
void FidoRequestHandlerBase::InitDiscoveries(
const base::flat_set<FidoTransportProtocol>& available_transports) {
// The number of times |notify_observer_callback_| needs to be invoked before // The number of times |notify_observer_callback_| needs to be invoked before
// Observer::OnTransportAvailabilityEnumerated is dispatched. Essentially this // Observer::OnTransportAvailabilityEnumerated is dispatched. Essentially this
// is used to wait until all the parts of |transport_availability_info_| are // is used to wait until all the parts of |transport_availability_info_| are
...@@ -85,7 +94,7 @@ FidoRequestHandlerBase::FidoRequestHandlerBase( ...@@ -85,7 +94,7 @@ FidoRequestHandlerBase::FidoRequestHandlerBase(
continue; continue;
} }
auto discovery = FidoDiscoveryFactory::Create(transport, connector); auto discovery = FidoDiscoveryFactory::Create(transport, connector_);
if (discovery == nullptr) { if (discovery == nullptr) {
// This can occur in tests when a ScopedVirtualU2fDevice is in effect and // This can occur in tests when a ScopedVirtualU2fDevice is in effect and
// HID transports are not configured. // HID transports are not configured.
...@@ -116,6 +125,55 @@ FidoRequestHandlerBase::FidoRequestHandlerBase( ...@@ -116,6 +125,55 @@ FidoRequestHandlerBase::FidoRequestHandlerBase(
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
#if defined(OS_WIN)
void FidoRequestHandlerBase::InitDiscoveriesWin(
const base::flat_set<FidoTransportProtocol>& available_transports) {
// Try to instantiate the discovery for proxying requests to the native
// Windows WebAuthn API; or fall back to using the regular device transport
// discoveries if the API is unavailable.
auto discovery = FidoDiscoveryFactory::MaybeCreateWinWebAuthnApiDiscovery();
if (!discovery) {
InitDiscoveries(available_transports);
return;
}
// The Windows WebAuthn API is available. On this platform, communicating
// with authenticator devices directly is blocked by the OS, so we need to go
// through the native API instead. No device discoveries may be instantiated.
//
// The Windows API supports USB, NFC, BLE and platform authenticators, but
// not caBLE. Communicating with caBLE devices directly is subject to the
// same block by the OS, so this platform is without caBLE support for now.
//
// TODO(martinkr): Re-enable the caBLE discovery once caBLE has moved to a
// different UUID. See crbug.com/905111.
discovery->set_observer(this);
discoveries_.push_back(std::move(discovery));
// Tell the embedder to not render a UI and ignore all future callbacks. Also
// don't report any available transports; the embedder is not supposed to use
// this information anyway.
transport_availability_info_.disable_embedder_ui = true;
transport_availability_info_.available_transports = {};
// The number of times |notify_observer_callback_| needs to be invoked before
// Observer::OnTransportAvailabilityEnumerated is dispatched. Essentially this
// is used to wait until all the parts of |transport_availability_info_| are
// filled out. In the case of Windows, there are no transport discoveries to
// wait for, so the |notify_observer_callback_| is only invoked in:
// 1) SetPlatformAuthenticatorOrMarkUnavailable().
// 2) set_observer().
constexpr size_t transport_info_callback_count = 2u;
notify_observer_callback_ = base::BarrierClosure(
transport_info_callback_count,
base::BindOnce(
&FidoRequestHandlerBase::NotifyObserverTransportAvailability,
weak_factory_.GetWeakPtr()));
}
#endif // defined(OS_WIN)
FidoRequestHandlerBase::~FidoRequestHandlerBase() = default; FidoRequestHandlerBase::~FidoRequestHandlerBase() = default;
void FidoRequestHandlerBase::StartAuthenticatorRequest( void FidoRequestHandlerBase::StartAuthenticatorRequest(
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/strings/string_piece_forward.h" #include "base/strings/string_piece_forward.h"
#include "build/build_config.h"
#include "device/fido/fido_device_authenticator.h" #include "device/fido/fido_device_authenticator.h"
#include "device/fido/fido_discovery_base.h" #include "device/fido/fido_discovery_base.h"
#include "device/fido/fido_transport_protocol.h" #include "device/fido/fido_transport_protocol.h"
...@@ -87,6 +88,12 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase ...@@ -87,6 +88,12 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
bool has_recognized_mac_touch_id_credential = false; bool has_recognized_mac_touch_id_credential = false;
bool is_ble_powered = false; bool is_ble_powered = false;
bool can_power_on_ble_adapter = false; bool can_power_on_ble_adapter = false;
// If true, dispatch of the request cannot be controlled by
// the embedder. The embedder must not display a UI for this
// request and must ignore all subsequent invocations of the
// TransportAvailabilityObserver interface methods.
bool disable_embedder_ui = false;
}; };
class COMPONENT_EXPORT(DEVICE_FIDO) TransportAvailabilityObserver { class COMPONENT_EXPORT(DEVICE_FIDO) TransportAvailabilityObserver {
...@@ -201,6 +208,13 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase ...@@ -201,6 +208,13 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
private: private:
friend class FidoRequestHandlerTest; friend class FidoRequestHandlerTest;
void InitDiscoveries(
const base::flat_set<FidoTransportProtocol>& available_transports);
#if defined(OS_WIN)
void InitDiscoveriesWin(
const base::flat_set<FidoTransportProtocol>& available_transports);
#endif
// FidoDiscoveryBase::Observer // FidoDiscoveryBase::Observer
void AuthenticatorAdded(FidoDiscoveryBase* discovery, void AuthenticatorAdded(FidoDiscoveryBase* discovery,
FidoAuthenticator* authenticator) final; FidoAuthenticator* authenticator) final;
...@@ -232,6 +246,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase ...@@ -232,6 +246,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
// TODO(martinkr): Inject platform authenticators through a new // TODO(martinkr): Inject platform authenticators through a new
// FidoDiscoveryBase specialization and hold ownership there. // FidoDiscoveryBase specialization and hold ownership there.
std::unique_ptr<FidoAuthenticator> platform_authenticator_; std::unique_ptr<FidoAuthenticator> platform_authenticator_;
service_manager::Connector* const connector_;
base::WeakPtrFactory<FidoRequestHandlerBase> weak_factory_; base::WeakPtrFactory<FidoRequestHandlerBase> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FidoRequestHandlerBase); DISALLOW_COPY_AND_ASSIGN(FidoRequestHandlerBase);
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN) #if defined(OS_WIN)
#include "device/fido/win/authenticator.h"
#include "device/fido/win/fake_webauthn_api.h" #include "device/fido/win/fake_webauthn_api.h"
#endif // defined(OS_WIN) #endif // defined(OS_WIN)
...@@ -753,10 +754,13 @@ TEST_F(GetAssertionRequestHandlerWinTest, TestWinUsbDiscovery) { ...@@ -753,10 +754,13 @@ TEST_F(GetAssertionRequestHandlerWinTest, TestWinUsbDiscovery) {
if (test.enable_feature_flag) if (test.enable_feature_flag)
scoped_feature_list.InitAndEnableFeature(kWebAuthUseNativeWinApi); scoped_feature_list.InitAndEnableFeature(kWebAuthUseNativeWinApi);
// Simulate a connected HID device.
ScopedFakeHidManager fake_hid_manager;
fake_hid_manager.AddFidoHidDevice("guid");
TestGetAssertionRequestCallback cb; TestGetAssertionRequestCallback cb;
ScopedFakeHidManager fake_hid_manager_;
auto handler = std::make_unique<GetAssertionRequestHandler>( auto handler = std::make_unique<GetAssertionRequestHandler>(
fake_hid_manager_.service_manager_connector(), fake_hid_manager.service_manager_connector(),
base::flat_set<FidoTransportProtocol>( base::flat_set<FidoTransportProtocol>(
{FidoTransportProtocol::kUsbHumanInterfaceDevice}), {FidoTransportProtocol::kUsbHumanInterfaceDevice}),
CtapGetAssertionRequest(test_data::kRelyingPartyId, CtapGetAssertionRequest(test_data::kRelyingPartyId,
...@@ -765,14 +769,11 @@ TEST_F(GetAssertionRequestHandlerWinTest, TestWinUsbDiscovery) { ...@@ -765,14 +769,11 @@ TEST_F(GetAssertionRequestHandlerWinTest, TestWinUsbDiscovery) {
cb.callback()); cb.callback());
scoped_task_environment_.RunUntilIdle(); scoped_task_environment_.RunUntilIdle();
fake_hid_manager_.AddFidoHidDevice("guid");
scoped_task_environment_.RunUntilIdle();
EXPECT_EQ(1u, handler->AuthenticatorsForTesting().size()); EXPECT_EQ(1u, handler->AuthenticatorsForTesting().size());
// Crudely distinguish authenticator type by FidoAuthenticator::GetId. // Crudely distinguish authenticator type by FidoAuthenticator::GetId.
EXPECT_EQ(test.expect_device_type == DeviceType::kHid EXPECT_EQ(test.expect_device_type == DeviceType::kHid
? "hid:guid" ? "hid:guid"
: "WinNativeCrossPlatformAuthenticator", : WinWebAuthnApiAuthenticator::kAuthenticatorId,
handler->AuthenticatorsForTesting().begin()->second->GetId()); handler->AuthenticatorsForTesting().begin()->second->GetId());
} }
} }
......
...@@ -39,7 +39,11 @@ base::string16 OptionalGURLToUTF16(const base::Optional<GURL>& in) { ...@@ -39,7 +39,11 @@ base::string16 OptionalGURLToUTF16(const base::Optional<GURL>& in) {
} // namespace } // namespace
WinNativeCrossPlatformAuthenticator::WinNativeCrossPlatformAuthenticator( // static
const char WinWebAuthnApiAuthenticator::kAuthenticatorId[] =
"WinWebAuthnApiAuthenticator";
WinWebAuthnApiAuthenticator::WinWebAuthnApiAuthenticator(
WinWebAuthnApi* win_api, WinWebAuthnApi* win_api,
HWND current_window) HWND current_window)
: FidoAuthenticator(), : FidoAuthenticator(),
...@@ -50,18 +54,18 @@ WinNativeCrossPlatformAuthenticator::WinNativeCrossPlatformAuthenticator( ...@@ -50,18 +54,18 @@ WinNativeCrossPlatformAuthenticator::WinNativeCrossPlatformAuthenticator(
CoCreateGuid(&cancellation_id_); CoCreateGuid(&cancellation_id_);
} }
WinNativeCrossPlatformAuthenticator::~WinNativeCrossPlatformAuthenticator() { WinWebAuthnApiAuthenticator::~WinWebAuthnApiAuthenticator() {
// Cancel in order to dismiss any pending API request and UI dialog and shut // Cancel in order to dismiss any pending API request and UI dialog and shut
// down |thread_|. // down |thread_|.
Cancel(); Cancel();
} }
void WinNativeCrossPlatformAuthenticator::InitializeAuthenticator( void WinWebAuthnApiAuthenticator::InitializeAuthenticator(
base::OnceClosure callback) { base::OnceClosure callback) {
std::move(callback).Run(); std::move(callback).Run();
} }
void WinNativeCrossPlatformAuthenticator::MakeCredential( void WinWebAuthnApiAuthenticator::MakeCredential(
CtapMakeCredentialRequest request, CtapMakeCredentialRequest request,
MakeCredentialCallback callback) { MakeCredentialCallback callback) {
DCHECK(!thread_); DCHECK(!thread_);
...@@ -78,22 +82,21 @@ void WinNativeCrossPlatformAuthenticator::MakeCredential( ...@@ -78,22 +82,21 @@ void WinNativeCrossPlatformAuthenticator::MakeCredential(
thread_->task_runner()->PostTask( thread_->task_runner()->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce( base::BindOnce(
&WinNativeCrossPlatformAuthenticator::MakeCredentialBlocking, &WinWebAuthnApiAuthenticator::MakeCredentialBlocking,
// Because |thread_| and its task runner are owned by this // Because |thread_| and its task runner are owned by this
// authenticator instance, binding to Unretained(this) here is // authenticator instance, binding to Unretained(this) here is
// fine. If the instance got destroyed before invocation of the // fine. If the instance got destroyed before invocation of the
// task, so would the task. Once the task is running, destruction // task, so would the task. Once the task is running, destruction
// of the authenticator instance blocks on the thread exiting. // of the authenticator instance blocks on the thread exiting.
base::Unretained(this), std::move(request), base::Unretained(this), std::move(request),
base::BindOnce(&WinNativeCrossPlatformAuthenticator:: base::BindOnce(
InvokeMakeCredentialCallback, &WinWebAuthnApiAuthenticator::InvokeMakeCredentialCallback,
weak_factory_.GetWeakPtr(), std::move(callback)), weak_factory_.GetWeakPtr(), std::move(callback)),
base::SequencedTaskRunnerHandle::Get())); base::SequencedTaskRunnerHandle::Get()));
} }
void WinNativeCrossPlatformAuthenticator::GetAssertion( void WinWebAuthnApiAuthenticator::GetAssertion(CtapGetAssertionRequest request,
CtapGetAssertionRequest request, GetAssertionCallback callback) {
GetAssertionCallback callback) {
DCHECK(!thread_); DCHECK(!thread_);
if (thread_) { if (thread_) {
return; return;
...@@ -104,7 +107,7 @@ void WinNativeCrossPlatformAuthenticator::GetAssertion( ...@@ -104,7 +107,7 @@ void WinNativeCrossPlatformAuthenticator::GetAssertion(
thread_->task_runner()->PostTask( thread_->task_runner()->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce( base::BindOnce(
&WinNativeCrossPlatformAuthenticator::GetAssertionBlocking, &WinWebAuthnApiAuthenticator::GetAssertionBlocking,
// Because |thread_| and its task runner are owned by this // Because |thread_| and its task runner are owned by this
// authenticator instance, binding to Unretained(this) here is // authenticator instance, binding to Unretained(this) here is
// fine. If the instance got destroyed before invocation of the // fine. If the instance got destroyed before invocation of the
...@@ -112,7 +115,7 @@ void WinNativeCrossPlatformAuthenticator::GetAssertion( ...@@ -112,7 +115,7 @@ void WinNativeCrossPlatformAuthenticator::GetAssertion(
// of the authenticator instance blocks on the thread exiting. // of the authenticator instance blocks on the thread exiting.
base::Unretained(this), std::move(request), base::Unretained(this), std::move(request),
base::BindOnce( base::BindOnce(
&WinNativeCrossPlatformAuthenticator::InvokeGetAssertionCallback, &WinWebAuthnApiAuthenticator::InvokeGetAssertionCallback,
weak_factory_.GetWeakPtr(), std::move(callback)), weak_factory_.GetWeakPtr(), std::move(callback)),
base::SequencedTaskRunnerHandle::Get())); base::SequencedTaskRunnerHandle::Get()));
} }
...@@ -120,7 +123,7 @@ void WinNativeCrossPlatformAuthenticator::GetAssertion( ...@@ -120,7 +123,7 @@ void WinNativeCrossPlatformAuthenticator::GetAssertion(
// Invokes the blocking WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL API call. This // Invokes the blocking WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL API call. This
// method is run on |thread_|. Note that the destructor for this class blocks // method is run on |thread_|. Note that the destructor for this class blocks
// on |thread_| shutdown. // on |thread_| shutdown.
void WinNativeCrossPlatformAuthenticator::MakeCredentialBlocking( void WinWebAuthnApiAuthenticator::MakeCredentialBlocking(
CtapMakeCredentialRequest request, CtapMakeCredentialRequest request,
MakeCredentialCallback callback, MakeCredentialCallback callback,
scoped_refptr<base::SequencedTaskRunner> callback_runner) { scoped_refptr<base::SequencedTaskRunner> callback_runner) {
...@@ -190,11 +193,10 @@ void WinNativeCrossPlatformAuthenticator::MakeCredentialBlocking( ...@@ -190,11 +193,10 @@ void WinNativeCrossPlatformAuthenticator::MakeCredentialBlocking(
kWinWebAuthnTimeoutMilliseconds, kWinWebAuthnTimeoutMilliseconds,
WEBAUTHN_CREDENTIALS{exclude_list.size(), exclude_list.data()}, WEBAUTHN_CREDENTIALS{exclude_list.size(), exclude_list.data()},
WEBAUTHN_EXTENSIONS{extensions.size(), extensions.data()}, WEBAUTHN_EXTENSIONS{extensions.size(), extensions.data()},
// Forcibly set authenticator attachment to cross-platform in order to // TODO(martinkr): Plumb authenticator attachment into
// avoid triggering the platform authenticator option, which is // CtapMakeCredentialRequest and set here.
// generally displayed first in the Windows UI.
use_u2f_only_ ? WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2 use_u2f_only_ ? WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2
: WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM, : WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY,
request.resident_key_required(), request.resident_key_required(),
ToWinUserVerificationRequirement(request.user_verification()), ToWinUserVerificationRequirement(request.user_verification()),
WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT, 0 /* flags */, WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT, 0 /* flags */,
...@@ -270,7 +272,7 @@ void WinNativeCrossPlatformAuthenticator::MakeCredentialBlocking( ...@@ -270,7 +272,7 @@ void WinNativeCrossPlatformAuthenticator::MakeCredentialBlocking(
// Invokes the blocking WEBAUTHN_AUTHENTICATOR_GET_ASSERTION API call. This // Invokes the blocking WEBAUTHN_AUTHENTICATOR_GET_ASSERTION API call. This
// method is run on |thread_|. Note that the destructor for this class blocks // method is run on |thread_|. Note that the destructor for this class blocks
// on |thread_| shutdown. // on |thread_| shutdown.
void WinNativeCrossPlatformAuthenticator::GetAssertionBlocking( void WinWebAuthnApiAuthenticator::GetAssertionBlocking(
CtapGetAssertionRequest request, CtapGetAssertionRequest request,
GetAssertionCallback callback, GetAssertionCallback callback,
scoped_refptr<base::SequencedTaskRunner> callback_runner) { scoped_refptr<base::SequencedTaskRunner> callback_runner) {
...@@ -298,8 +300,10 @@ void WinNativeCrossPlatformAuthenticator::GetAssertionBlocking( ...@@ -298,8 +300,10 @@ void WinNativeCrossPlatformAuthenticator::GetAssertionBlocking(
kWinWebAuthnTimeoutMilliseconds, kWinWebAuthnTimeoutMilliseconds,
WEBAUTHN_CREDENTIALS{allow_list.size(), allow_list.data()}, WEBAUTHN_CREDENTIALS{allow_list.size(), allow_list.data()},
WEBAUTHN_EXTENSIONS{0, nullptr}, WEBAUTHN_EXTENSIONS{0, nullptr},
// TODO(martinkr): Plumb authenticator attachment into
// CtapMakeCredentialRequest and set here.
use_u2f_only_ ? WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2 use_u2f_only_ ? WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2
: WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM, : WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY,
ToWinUserVerificationRequirement(request.user_verification()), ToWinUserVerificationRequirement(request.user_verification()),
0, // flags 0, // flags
use_u2f_only_ ? rp_id16.c_str() : nullptr, // pwszU2fAppId use_u2f_only_ ? rp_id16.c_str() : nullptr, // pwszU2fAppId
...@@ -333,7 +337,7 @@ void WinNativeCrossPlatformAuthenticator::GetAssertionBlocking( ...@@ -333,7 +337,7 @@ void WinNativeCrossPlatformAuthenticator::GetAssertionBlocking(
base::BindOnce(std::move(callback), status, std::move(response))); base::BindOnce(std::move(callback), status, std::move(response)));
} }
void WinNativeCrossPlatformAuthenticator::Cancel() { void WinWebAuthnApiAuthenticator::Cancel() {
if (!thread_ || operation_cancelled_.IsSet()) { if (!thread_ || operation_cancelled_.IsSet()) {
return; return;
} }
...@@ -345,31 +349,31 @@ void WinNativeCrossPlatformAuthenticator::Cancel() { ...@@ -345,31 +349,31 @@ void WinNativeCrossPlatformAuthenticator::Cancel() {
thread_->Stop(); thread_->Stop();
} }
std::string WinNativeCrossPlatformAuthenticator::GetId() const { std::string WinWebAuthnApiAuthenticator::GetId() const {
return "WinNativeCrossPlatformAuthenticator"; return kAuthenticatorId;
} }
base::string16 WinNativeCrossPlatformAuthenticator::GetDisplayName() const { base::string16 WinWebAuthnApiAuthenticator::GetDisplayName() const {
return L"WinNativeCrossPlatformAuthenticator"; return base::UTF8ToUTF16(GetId());
} }
bool WinNativeCrossPlatformAuthenticator::IsInPairingMode() const { bool WinWebAuthnApiAuthenticator::IsInPairingMode() const {
return false; return false;
} }
bool WinNativeCrossPlatformAuthenticator::IsPaired() const { bool WinWebAuthnApiAuthenticator::IsPaired() const {
return false; return false;
} }
base::Optional<FidoTransportProtocol> base::Optional<FidoTransportProtocol>
WinNativeCrossPlatformAuthenticator::AuthenticatorTransport() const { WinWebAuthnApiAuthenticator::AuthenticatorTransport() const {
// The Windows API could potentially use any external or // The Windows API could potentially use any external or
// platform authenticator. // platform authenticator.
return base::nullopt; return base::nullopt;
} }
const base::Optional<AuthenticatorSupportedOptions>& const base::Optional<AuthenticatorSupportedOptions>&
WinNativeCrossPlatformAuthenticator::Options() const { WinWebAuthnApiAuthenticator::Options() const {
// The request can potentially be fulfilled by any device that Windows // The request can potentially be fulfilled by any device that Windows
// communicates with, so returning AuthenticatorSupportedOptions really // communicates with, so returning AuthenticatorSupportedOptions really
// doesn't make much sense. // doesn't make much sense.
...@@ -378,12 +382,11 @@ WinNativeCrossPlatformAuthenticator::Options() const { ...@@ -378,12 +382,11 @@ WinNativeCrossPlatformAuthenticator::Options() const {
return no_options; return no_options;
} }
base::WeakPtr<FidoAuthenticator> base::WeakPtr<FidoAuthenticator> WinWebAuthnApiAuthenticator::GetWeakPtr() {
WinNativeCrossPlatformAuthenticator::GetWeakPtr() {
return weak_factory_.GetWeakPtr(); return weak_factory_.GetWeakPtr();
} }
void WinNativeCrossPlatformAuthenticator::InvokeMakeCredentialCallback( void WinWebAuthnApiAuthenticator::InvokeMakeCredentialCallback(
MakeCredentialCallback cb, MakeCredentialCallback cb,
CtapDeviceResponseCode status, CtapDeviceResponseCode status,
base::Optional<AuthenticatorMakeCredentialResponse> response) { base::Optional<AuthenticatorMakeCredentialResponse> response) {
...@@ -394,7 +397,7 @@ void WinNativeCrossPlatformAuthenticator::InvokeMakeCredentialCallback( ...@@ -394,7 +397,7 @@ void WinNativeCrossPlatformAuthenticator::InvokeMakeCredentialCallback(
} }
std::move(cb).Run(status, std::move(response)); std::move(cb).Run(status, std::move(response));
} }
void WinNativeCrossPlatformAuthenticator::InvokeGetAssertionCallback( void WinWebAuthnApiAuthenticator::InvokeGetAssertionCallback(
GetAssertionCallback cb, GetAssertionCallback cb,
CtapDeviceResponseCode status, CtapDeviceResponseCode status,
base::Optional<AuthenticatorGetAssertionResponse> response) { base::Optional<AuthenticatorGetAssertionResponse> response) {
......
...@@ -20,15 +20,17 @@ ...@@ -20,15 +20,17 @@
namespace device { namespace device {
// WinNativeCrossPlatformAuthenticator forwards WebAuthn requests to external // WinWebAuthnApiAuthenticator forwards WebAuthn requests to external
// authenticators via the native Windows WebAuthentication API // authenticators via the native Windows WebAuthentication API
// (webauthn.dll). // (webauthn.dll).
class COMPONENT_EXPORT(DEVICE_FIDO) WinNativeCrossPlatformAuthenticator class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApiAuthenticator
: public FidoAuthenticator { : public FidoAuthenticator {
public: public:
WinNativeCrossPlatformAuthenticator(WinWebAuthnApi* win_api, // The return value of |GetId|.
HWND current_window); static const char kAuthenticatorId[];
~WinNativeCrossPlatformAuthenticator() override;
WinWebAuthnApiAuthenticator(WinWebAuthnApi* win_api, HWND current_window);
~WinWebAuthnApiAuthenticator() override;
// Forces the Windows WebAuthn API not to communicate with CTAP2 devices for // Forces the Windows WebAuthn API not to communicate with CTAP2 devices for
// this request. Dual-protocol devices will use U2F. // this request. Dual-protocol devices will use U2F.
...@@ -84,8 +86,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) WinNativeCrossPlatformAuthenticator ...@@ -84,8 +86,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) WinNativeCrossPlatformAuthenticator
GUID cancellation_id_ = {}; GUID cancellation_id_ = {};
base::AtomicFlag operation_cancelled_; base::AtomicFlag operation_cancelled_;
base::WeakPtrFactory<WinNativeCrossPlatformAuthenticator> weak_factory_; base::WeakPtrFactory<WinWebAuthnApiAuthenticator> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(WinNativeCrossPlatformAuthenticator); DISALLOW_COPY_AND_ASSIGN(WinWebAuthnApiAuthenticator);
}; };
} // namespace device } // namespace device
......
...@@ -6,18 +6,17 @@ ...@@ -6,18 +6,17 @@
namespace device { namespace device {
WinNativeCrossPlatformAuthenticatorDiscovery:: WinWebAuthnApiAuthenticatorDiscovery::WinWebAuthnApiAuthenticatorDiscovery(
WinNativeCrossPlatformAuthenticatorDiscovery( WinWebAuthnApi* const win_webauthn_api,
WinWebAuthnApi* const win_webauthn_api, HWND parent_window)
HWND parent_window)
: FidoDiscoveryBase(FidoTransportProtocol::kUsbHumanInterfaceDevice), : FidoDiscoveryBase(FidoTransportProtocol::kUsbHumanInterfaceDevice),
win_webauthn_api_(win_webauthn_api), win_webauthn_api_(win_webauthn_api),
parent_window_(parent_window) {} parent_window_(parent_window) {}
WinNativeCrossPlatformAuthenticatorDiscovery:: WinWebAuthnApiAuthenticatorDiscovery::~WinWebAuthnApiAuthenticatorDiscovery() =
~WinNativeCrossPlatformAuthenticatorDiscovery() = default; default;
void WinNativeCrossPlatformAuthenticatorDiscovery::Start() { void WinWebAuthnApiAuthenticatorDiscovery::Start() {
DCHECK(!authenticator_); DCHECK(!authenticator_);
if (!observer()) { if (!observer()) {
return; return;
...@@ -29,7 +28,7 @@ void WinNativeCrossPlatformAuthenticatorDiscovery::Start() { ...@@ -29,7 +28,7 @@ void WinNativeCrossPlatformAuthenticatorDiscovery::Start() {
} }
observer()->DiscoveryStarted(this, true /* success */); observer()->DiscoveryStarted(this, true /* success */);
authenticator_ = std::make_unique<WinNativeCrossPlatformAuthenticator>( authenticator_ = std::make_unique<WinWebAuthnApiAuthenticator>(
WinWebAuthnApi::GetDefault(), parent_window_); WinWebAuthnApi::GetDefault(), parent_window_);
observer()->AuthenticatorAdded(this, authenticator_.get()); observer()->AuthenticatorAdded(this, authenticator_.get());
} }
......
...@@ -16,19 +16,18 @@ namespace device { ...@@ -16,19 +16,18 @@ 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 COMPONENT_EXPORT(DEVICE_FIDO) WinNativeCrossPlatformAuthenticatorDiscovery class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApiAuthenticatorDiscovery
: public FidoDiscoveryBase { : public FidoDiscoveryBase {
public: public:
WinNativeCrossPlatformAuthenticatorDiscovery( WinWebAuthnApiAuthenticatorDiscovery(WinWebAuthnApi* const win_webauthn_api,
WinWebAuthnApi* const win_webauthn_api, HWND parent_window);
HWND parent_window); ~WinWebAuthnApiAuthenticatorDiscovery() override;
~WinNativeCrossPlatformAuthenticatorDiscovery() override;
// FidoDiscoveryBase: // FidoDiscoveryBase:
void Start() override; void Start() override;
private: private:
std::unique_ptr<WinNativeCrossPlatformAuthenticator> authenticator_; std::unique_ptr<WinWebAuthnApiAuthenticator> authenticator_;
WinWebAuthnApi* const win_webauthn_api_; WinWebAuthnApi* const win_webauthn_api_;
const HWND parent_window_; const HWND parent_window_;
}; };
......
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