blob: 1c360e38d20086f144999c5cab0e312f3f7a5d04 [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_H_
#define DEVICE_FIDO_FIDO_REQUEST_HANDLER_H_
#include "device/fido/fido_request_handler_base.h"
#include <utility>
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/optional.h"
#include "device/fido/fido_authenticator.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_device.h"
#include "device/fido/fido_transport_protocol.h"
namespace device {
// Handles receiving response form potentially multiple connected authenticators
// and relaying response to the relying party.
template <class Response>
class FidoRequestHandler : public FidoRequestHandlerBase {
public:
using CompletionCallback =
base::OnceCallback<void(FidoReturnCode status_code,
base::Optional<Response> response_data)>;
FidoRequestHandler(service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& transports,
CompletionCallback completion_callback)
: FidoRequestHandler(connector,
transports,
std::move(completion_callback),
AddPlatformAuthenticatorCallback()) {}
FidoRequestHandler(
service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& transports,
CompletionCallback completion_callback,
AddPlatformAuthenticatorCallback add_platform_authenticator)
: FidoRequestHandlerBase(connector,
transports,
std::move(add_platform_authenticator)),
completion_callback_(std::move(completion_callback)) {}
~FidoRequestHandler() override {
if (!is_complete())
CancelOngoingTasks();
}
bool is_complete() const { return completion_callback_.is_null(); }
protected:
// Converts authenticator response code received from CTAP1/CTAP2 device into
// FidoReturnCode and passes response data to webauth::mojom::Authenticator.
void OnAuthenticatorResponse(FidoAuthenticator* authenticator,
CtapDeviceResponseCode device_response_code,
base::Optional<Response> response_data) {
if (is_complete()) {
DVLOG(2)
<< "Response from authenticator received after request is complete.";
return;
}
const auto return_code = ConvertDeviceResponseCodeToFidoReturnCode(
device_response_code, response_data.has_value());
// Any authenticator response codes that do not result from user consent
// imply that the authenticator should be dropped and that other on-going
// requests should continue until timeout is reached.
if (!return_code) {
active_authenticators().erase(authenticator->GetId());
return;
}
// Once response has been passed to the relying party, cancel all other on
// going requests.
CancelOngoingTasks(authenticator->GetId());
std::move(completion_callback_).Run(*return_code, std::move(response_data));
}
private:
static base::Optional<FidoReturnCode>
ConvertDeviceResponseCodeToFidoReturnCode(
CtapDeviceResponseCode device_response_code,
bool response_has_value) {
switch (device_response_code) {
case CtapDeviceResponseCode::kSuccess:
return response_has_value
? FidoReturnCode::kSuccess
: FidoReturnCode::kAuthenticatorResponseInvalid;
// These errors are only returned after the user interacted with the
// authenticator.
case CtapDeviceResponseCode::kCtap2ErrCredentialExcluded:
return FidoReturnCode::kUserConsentButCredentialExcluded;
case CtapDeviceResponseCode::kCtap2ErrInvalidCredential:
case CtapDeviceResponseCode::kCtap2ErrCredentialNotValid:
case CtapDeviceResponseCode::kCtap2ErrNoCredentials:
return FidoReturnCode::kUserConsentButCredentialNotRecognized;
// For all other errors, the authenticator will be dropped, and other
// authenticators may continue.
default:
return base::nullopt;
}
}
CompletionCallback completion_callback_;
DISALLOW_COPY_AND_ASSIGN(FidoRequestHandler);
};
} // namespace device
#endif // DEVICE_FIDO_FIDO_REQUEST_HANDLER_H_