| // 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; |
| default: |
| return base::nullopt; |
| } |
| } |
| |
| CompletionCallback completion_callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(FidoRequestHandler); |
| }; |
| |
| } // namespace device |
| |
| #endif // DEVICE_FIDO_FIDO_REQUEST_HANDLER_H_ |