blob: bdb974d5afe9efb552ee752746ddcec5d2ae95b4 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_WEBAUTHN_CHROME_AUTHENTICATOR_REQUEST_DELEGATE_H_
#define CHROME_BROWSER_WEBAUTHN_CHROME_AUTHENTICATOR_REQUEST_DELEGATE_H_
#include <memory>
#include <string>
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/webauthn/authenticator_request_dialog_model.h"
#include "content/public/browser/authenticator_request_client_delegate.h"
#include "content/public/browser/global_routing_id.h"
#include "device/fido/cable/cable_discovery_data.h"
#include "device/fido/fido_request_handler_base.h"
#include "device/fido/fido_transport_protocol.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
class Profile;
namespace content {
class BrowserContext;
class RenderFrameHost;
} // namespace content
namespace device {
class PublicKeyCredentialDescriptor;
class PublicKeyCredentialUserEntity;
} // namespace device
namespace user_prefs {
class PrefRegistrySyncable;
}
namespace device {
class FidoAuthenticator;
class FidoDiscoveryFactory;
} // namespace device
// ChromeWebAuthenticationDelegate is the //chrome layer implementation of
// content::WebAuthenticationDelegate.
class ChromeWebAuthenticationDelegate
: public content::WebAuthenticationDelegate {
public:
#if BUILDFLAG(IS_MAC)
// Returns a configuration struct for instantiating the macOS WebAuthn
// platform authenticator for the given Profile.
static TouchIdAuthenticatorConfig TouchIdAuthenticatorConfigForProfile(
Profile* profile);
#endif // BUILDFLAG(IS_MAC)
~ChromeWebAuthenticationDelegate() override;
#if !BUILDFLAG(IS_ANDROID)
// content::WebAuthenticationDelegate:
bool OverrideCallerOriginAndRelyingPartyIdValidation(
content::BrowserContext* browser_context,
const url::Origin& caller_origin,
const std::string& relying_party_id) override;
bool OriginMayUseRemoteDesktopClientOverride(
content::BrowserContext* browser_context,
const url::Origin& caller_origin) override;
bool IsSecurityLevelAcceptableForWebAuthn(
content::RenderFrameHost* rfh,
const url::Origin& caller_origin) override;
absl::optional<std::string> MaybeGetRelyingPartyIdOverride(
const std::string& claimed_relying_party_id,
const url::Origin& caller_origin) override;
bool ShouldPermitIndividualAttestation(
content::BrowserContext* browser_context,
const url::Origin& caller_origin,
const std::string& relying_party_id) override;
bool SupportsResidentKeys(
content::RenderFrameHost* render_frame_host) override;
bool IsFocused(content::WebContents* web_contents) override;
absl::optional<bool> IsUserVerifyingPlatformAuthenticatorAvailableOverride(
content::RenderFrameHost* render_frame_host) override;
content::WebAuthenticationRequestProxy* MaybeGetRequestProxy(
content::BrowserContext* browser_context,
const url::Origin& caller_origin) override;
#endif
#if BUILDFLAG(IS_MAC)
absl::optional<TouchIdAuthenticatorConfig> GetTouchIdAuthenticatorConfig(
content::BrowserContext* browser_context) override;
#endif // BUILDFLAG(IS_MAC)
#if BUILDFLAG(IS_CHROMEOS)
ChromeOSGenerateRequestIdCallback GetGenerateRequestIdCallback(
content::RenderFrameHost* render_frame_host) override;
#endif // BUILDFLAG(IS_CHROMEOS)
};
class ChromeAuthenticatorRequestDelegate
: public content::AuthenticatorRequestClientDelegate,
public AuthenticatorRequestDialogModel::Observer {
public:
// TestObserver is an interface that observes certain events related to this
// class for testing purposes. Only a single instance of this interface can
// be installed at a given time.
class TestObserver {
public:
virtual void Created(ChromeAuthenticatorRequestDelegate* delegate) = 0;
virtual std::vector<std::unique_ptr<device::cablev2::Pairing>>
GetCablePairingsFromSyncedDevices() = 0;
virtual void OnTransportAvailabilityEnumerated(
ChromeAuthenticatorRequestDelegate* delegate,
device::FidoRequestHandlerBase::TransportAvailabilityInfo* tai) = 0;
virtual void UIShown(ChromeAuthenticatorRequestDelegate* delegate) = 0;
virtual void CableV2ExtensionSeen(
base::span<const uint8_t> server_link_data) = 0;
virtual void ConfiguringCable(device::FidoRequestType request_type) {}
virtual void AccountSelectorShown(
const std::vector<device::AuthenticatorGetAssertionResponse>&
responses) {}
};
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
// The |render_frame_host| must outlive this instance.
explicit ChromeAuthenticatorRequestDelegate(
content::RenderFrameHost* render_frame_host);
ChromeAuthenticatorRequestDelegate(
const ChromeAuthenticatorRequestDelegate&) = delete;
ChromeAuthenticatorRequestDelegate& operator=(
const ChromeAuthenticatorRequestDelegate&) = delete;
~ChromeAuthenticatorRequestDelegate() override;
// SetGlobalObserverForTesting sets the single |TestObserver| that is active
// at a given time. Call be called with |nullptr| to unregister a
// |TestObserver|. It is a fatal error to try and register a |TestObserver|
// while one is still installed.
static void SetGlobalObserverForTesting(TestObserver*);
base::WeakPtr<ChromeAuthenticatorRequestDelegate> AsWeakPtr();
AuthenticatorRequestDialogModel* dialog_model() const {
return dialog_model_.get();
}
// content::AuthenticatorRequestClientDelegate:
void SetRelyingPartyId(const std::string& rp_id) override;
bool DoesBlockRequestOnFailure(InterestingFailureReason reason) override;
void RegisterActionCallbacks(
base::OnceClosure cancel_callback,
base::RepeatingClosure start_over_callback,
AccountPreselectedCallback account_preselected_callback,
device::FidoRequestHandlerBase::RequestCallback request_callback,
base::RepeatingClosure bluetooth_adapter_power_on_callback) override;
void ShouldReturnAttestation(
const std::string& relying_party_id,
const device::FidoAuthenticator* authenticator,
bool is_enterprise_attestation,
base::OnceCallback<void(bool)> callback) override;
void ConfigureCable(
const url::Origin& origin,
device::FidoRequestType request_type,
absl::optional<device::ResidentKeyRequirement> resident_key_requirement,
base::span<const device::CableDiscoveryData> pairings_from_extension,
device::FidoDiscoveryFactory* discovery_factory) override;
void SelectAccount(
std::vector<device::AuthenticatorGetAssertionResponse> responses,
base::OnceCallback<void(device::AuthenticatorGetAssertionResponse)>
callback) override;
void DisableUI() override;
bool IsWebAuthnUIEnabled() override;
void SetConditionalRequest(bool is_conditional) override;
void SetCredentialIdFilter(std::vector<device::PublicKeyCredentialDescriptor>
credential_list) override;
void SetUserEntityForMakeCredentialRequest(
const device::PublicKeyCredentialUserEntity& user_entity) override;
// device::FidoRequestHandlerBase::Observer:
void OnTransportAvailabilityEnumerated(
device::FidoRequestHandlerBase::TransportAvailabilityInfo data) override;
bool EmbedderControlsAuthenticatorDispatch(
const device::FidoAuthenticator& authenticator) override;
void FidoAuthenticatorAdded(
const device::FidoAuthenticator& authenticator) override;
void FidoAuthenticatorRemoved(base::StringPiece authenticator_id) override;
void BluetoothAdapterPowerChanged(bool is_powered_on) override;
bool SupportsPIN() const override;
void CollectPIN(
CollectPINOptions options,
base::OnceCallback<void(std::u16string)> provide_pin_cb) override;
void StartBioEnrollment(base::OnceClosure next_callback) override;
void OnSampleCollected(int bio_samples_remaining) override;
void FinishCollectToken() override;
void OnRetryUserVerification(int attempts) override;
// AuthenticatorRequestDialogModel::Observer:
void OnStartOver() override;
void OnModelDestroyed(AuthenticatorRequestDialogModel* model) override;
void OnCancelRequest() override;
void OnManageDevicesClicked() override;
// A non-const version of dialog_model().
AuthenticatorRequestDialogModel* GetDialogModelForTesting();
// SetPassEmptyUsbDeviceManagerForTesting controls whether the
// `DiscoveryFactory` will be given an empty USB device manager. This is
// needed in tests because creating a real `device::mojom::UsbDeviceManager`
// can create objects on thread-pool threads. Those objects aren't scheduled
// for deletion until after the thread-pool is shutdown when testing, causing
// "leaks" to be reported.
void SetPassEmptyUsbDeviceManagerForTesting(bool value);
FRIEND_TEST_ALL_PREFIXES(ChromeAuthenticatorRequestDelegateTest,
TestTransportPrefType);
FRIEND_TEST_ALL_PREFIXES(ChromeAuthenticatorRequestDelegateTest,
TestPairedDeviceAddressPreference);
// GetRenderFrameHost returns a pointer to the RenderFrameHost that was given
// to the constructor.
content::RenderFrameHost* GetRenderFrameHost() const;
content::BrowserContext* GetBrowserContext() const;
absl::optional<device::FidoTransportProtocol> GetLastTransportUsed() const;
// ShouldPermitCableExtension returns true if the given |origin| may set a
// caBLE extension. This extension contains website-chosen BLE pairing
// information that will be broadcast by the device.
bool ShouldPermitCableExtension(const url::Origin& origin);
void OnInvalidatedCablePairing(size_t failed_contact_index);
const content::GlobalRenderFrameHostId render_frame_host_id_;
const std::unique_ptr<AuthenticatorRequestDialogModel> dialog_model_;
base::OnceClosure cancel_callback_;
base::RepeatingClosure start_over_callback_;
AccountPreselectedCallback account_preselected_callback_;
device::FidoRequestHandlerBase::RequestCallback request_callback_;
// The next two fields are the same length and contain the names and public
// keys of paired phones.
std::vector<std::string> phone_names_;
std::vector<std::array<uint8_t, device::kP256X962Length>> phone_public_keys_;
// 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;
// If true, show a more subtle UI unless the user has platform discoverable
// credentials on the device.
bool is_conditional_ = false;
// A list of credentials used to filter passkeys by ID. When non-empty,
// non-matching passkeys will not be displayed during conditional mediation
// requests. When empty, no filter is applied and all passkeys are displayed.
std::vector<device::PublicKeyCredentialDescriptor> credential_filter_;
// See `SetPassEmptyUsbDeviceManagerForTesting`.
bool pass_empty_usb_device_manager_ = false;
private:
base::WeakPtrFactory<ChromeAuthenticatorRequestDelegate> weak_ptr_factory_{
this};
};
#endif // CHROME_BROWSER_WEBAUTHN_CHROME_AUTHENTICATOR_REQUEST_DELEGATE_H_