blob: 8253124379b4cacb06879ca0cbde6251a9113196 [file] [log] [blame]
// 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_FIDO_REQUEST_HANDLER_BASE_H_
#define DEVICE_FIDO_FIDO_REQUEST_HANDLER_BASE_H_
#include <functional>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/component_export.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_piece_forward.h"
#include "device/fido/fido_device_authenticator.h"
#include "device/fido/fido_discovery.h"
#include "device/fido/fido_transport_protocol.h"
namespace service_manager {
class Connector;
}; // namespace service_manager
namespace device {
class FidoAuthenticator;
class FidoDevice;
class FidoTask;
// Base class that handles device discovery/removal. Each FidoRequestHandlerBase
// is owned by FidoRequestManager and its lifetime is equivalent to that of a
// single WebAuthn request. For each authenticator, the per-device work is
// carried out by one FidoTask instance, which is constructed on DeviceAdded(),
// and destroyed either on DeviceRemoved() or CancelOutgoingTaks().
class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
: public FidoDiscovery::Observer {
public:
using AuthenticatorMap =
std::map<std::string, std::unique_ptr<FidoAuthenticator>, std::less<>>;
using AddPlatformAuthenticatorCallback =
base::OnceCallback<std::unique_ptr<FidoAuthenticator>()>;
enum class RequestType { kMakeCredential, kGetAssertion };
// Encapsulates data required to initiate WebAuthN UX dialog. Once all
// components of TransportAvailabilityInfo is set,
// AuthenticatorRequestClientDelegate should be notified.
// TODO(hongjunchoi): Add async calls to notify embedder when Bluetooth is
// powered on/off.
struct COMPONENT_EXPORT(DEVICE_FIDO) TransportAvailabilityInfo {
TransportAvailabilityInfo();
TransportAvailabilityInfo(const TransportAvailabilityInfo& other);
TransportAvailabilityInfo& operator=(
const TransportAvailabilityInfo& other);
~TransportAvailabilityInfo();
RequestType request_type = RequestType::kMakeCredential;
std::set<FidoTransportProtocol> available_transports;
bool has_recognized_mac_touch_id_credential = false;
bool is_ble_powered = false;
bool can_power_on_ble_adapter = false;
};
class COMPONENT_EXPORT(DEVICE_FIDO) TransportAvailabilityObserver {
public:
virtual ~TransportAvailabilityObserver();
virtual void OnTransportAvailabilityEnumerated(
TransportAvailabilityInfo data) = 0;
virtual void BluetoothAdapterPowerChanged(bool is_powered_on) = 0;
virtual void FidoAuthenticatorAdded(
const FidoAuthenticator& authenticator) = 0;
virtual void FidoAuthenticatorRemoved(base::StringPiece device_id) = 0;
};
// TODO(https://crbug.com/769631): Remove the dependency on Connector once
// device/fido is servicified.
FidoRequestHandlerBase(
service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& transports);
FidoRequestHandlerBase(
service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& transports,
AddPlatformAuthenticatorCallback add_platform_authenticator);
~FidoRequestHandlerBase() override;
// Triggers cancellation of all per-device FidoTasks, except for the device
// with |exclude_device_id|, if one is provided. Cancelled tasks are
// immediately removed from |ongoing_tasks_|.
//
// This function is invoked either when:
// (a) the entire WebAuthn API request is canceled or,
// (b) a successful response or "invalid state error" is received from the
// any one of the connected authenticators, in which case all other
// per-device tasks are cancelled.
// https://w3c.github.io/webauthn/#iface-pkcredential
void CancelOngoingTasks(base::StringPiece exclude_device_id = nullptr);
void set_observer(TransportAvailabilityObserver* observer) {
DCHECK(!observer_) << "Only one observer is supported.";
observer_ = observer;
}
protected:
virtual base::WeakPtr<FidoRequestHandlerBase> GetWeakPtr() = 0;
// Subclasses implement this method to dispatch their request onto the given
// FidoAuthenticator. The FidoAuthenticator is owned by this
// FidoRequestHandler and stored in active_authenticators().
virtual void DispatchRequest(FidoAuthenticator*) = 0;
void Start();
// Testing seam to allow unit tests to inject a fake authenticator.
virtual std::unique_ptr<FidoDeviceAuthenticator>
CreateAuthenticatorFromDevice(FidoDevice* device);
AuthenticatorMap& active_authenticators() { return active_authenticators_; }
std::vector<std::unique_ptr<FidoDiscovery>>& discoveries() {
return discoveries_;
}
TransportAvailabilityInfo& transport_availability_info() {
return transport_availability_info_;
}
TransportAvailabilityObserver* observer() const { return observer_; }
private:
// FidoDiscovery::Observer
void DiscoveryStarted(FidoDiscovery* discovery, bool success) final;
void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) final;
void DeviceRemoved(FidoDiscovery* discovery, FidoDevice* device) final;
void BluetoothAdapterPowerChanged(bool is_powered_on) final;
void AddAuthenticator(std::unique_ptr<FidoAuthenticator> authenticator);
void MaybeAddPlatformAuthenticator();
void NotifyObserverUiData();
AuthenticatorMap active_authenticators_;
std::vector<std::unique_ptr<FidoDiscovery>> discoveries_;
TransportAvailabilityObserver* observer_ = nullptr;
TransportAvailabilityInfo transport_availability_info_;
base::RepeatingClosure notify_observer_callback_;
AddPlatformAuthenticatorCallback add_platform_authenticator_;
base::WeakPtrFactory<FidoRequestHandlerBase> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FidoRequestHandlerBase);
};
} // namespace device
#endif // DEVICE_FIDO_FIDO_REQUEST_HANDLER_BASE_H_