remote_webauthn_message_handler.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "remoting/host/webauthn/remote_webauthn_message_handler.h"
  5. #include <stdint.h>
  6. #include <limits>
  7. #include "base/bind.h"
  8. #include "base/callback_helpers.h"
  9. #include "base/containers/contains.h"
  10. #include "base/logging.h"
  11. #include "base/notreached.h"
  12. #include "remoting/host/mojom/webauthn_proxy.mojom.h"
  13. #include "remoting/host/webauthn/remote_webauthn_state_change_notifier.h"
  14. #include "remoting/proto/remote_webauthn.pb.h"
  15. #include "remoting/protocol/message_serialization.h"
  16. namespace remoting {
  17. namespace {
  18. template <typename CallbackType, typename... ResponseType>
  19. void FindAndRunCallback(base::flat_map<uint64_t, CallbackType>& callback_map,
  20. uint64_t id,
  21. ResponseType&&... response) {
  22. auto it = callback_map.find(id);
  23. if (it == callback_map.end()) {
  24. LOG(WARNING) << "No callback found associated with ID: " << id;
  25. return;
  26. }
  27. std::move(it->second).Run(std::forward<ResponseType>(response)...);
  28. callback_map.erase(it);
  29. }
  30. mojom::WebAuthnExceptionDetailsPtr ProtobufErrorToMojoError(
  31. const protocol::RemoteWebAuthn::ExceptionDetails& pb_error) {
  32. auto mojo_error = mojom::WebAuthnExceptionDetails::New();
  33. mojo_error->name = pb_error.name();
  34. mojo_error->message = pb_error.message();
  35. return mojo_error;
  36. }
  37. mojom::WebAuthnExceptionDetailsPtr CreateMojoAbortError() {
  38. auto mojo_error = mojom::WebAuthnExceptionDetails::New();
  39. mojo_error->name = "AbortError";
  40. mojo_error->message = "Request has been canceled by the host.";
  41. return mojo_error;
  42. }
  43. } // namespace
  44. RemoteWebAuthnMessageHandler::RemoteWebAuthnMessageHandler(
  45. const std::string& name,
  46. std::unique_ptr<protocol::MessagePipe> pipe,
  47. std::unique_ptr<RemoteWebAuthnStateChangeNotifier> state_change_notifier)
  48. : protocol::NamedMessagePipeHandler(name, std::move(pipe)) {
  49. state_change_notifier_ = std::move(state_change_notifier);
  50. receiver_set_.set_disconnect_handler(
  51. base::BindRepeating(&RemoteWebAuthnMessageHandler::OnReceiverDisconnected,
  52. base::Unretained(this)));
  53. request_cancellers_.set_disconnect_handler(base::BindRepeating(
  54. &RemoteWebAuthnMessageHandler::OnRequestCancellerDisconnected,
  55. base::Unretained(this)));
  56. }
  57. RemoteWebAuthnMessageHandler::~RemoteWebAuthnMessageHandler() {
  58. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  59. DCHECK(!connected());
  60. }
  61. void RemoteWebAuthnMessageHandler::OnConnected() {
  62. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  63. NotifyWebAuthnStateChange();
  64. }
  65. void RemoteWebAuthnMessageHandler::OnIncomingMessage(
  66. std::unique_ptr<CompoundBuffer> message) {
  67. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  68. auto remote_webauthn =
  69. protocol::ParseMessage<protocol::RemoteWebAuthn>(message.get());
  70. if (!remote_webauthn->has_id()) {
  71. LOG(ERROR) << "Response doesn't have a message ID.";
  72. return;
  73. }
  74. switch (remote_webauthn->message_case()) {
  75. case protocol::RemoteWebAuthn::kIsUvpaaResponse:
  76. OnIsUvpaaResponse(remote_webauthn->id(),
  77. remote_webauthn->is_uvpaa_response());
  78. break;
  79. case protocol::RemoteWebAuthn::kCreateResponse:
  80. OnCreateResponse(remote_webauthn->id(),
  81. remote_webauthn->create_response());
  82. break;
  83. case protocol::RemoteWebAuthn::kGetResponse:
  84. OnGetResponse(remote_webauthn->id(), remote_webauthn->get_response());
  85. break;
  86. case protocol::RemoteWebAuthn::kCancelResponse:
  87. OnCancelResponse(remote_webauthn->id(),
  88. remote_webauthn->cancel_response());
  89. break;
  90. default:
  91. LOG(ERROR) << "Unknown message case: " << remote_webauthn->message_case();
  92. }
  93. }
  94. void RemoteWebAuthnMessageHandler::OnDisconnecting() {
  95. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  96. // Run mojo callbacks with error/default response then clean them up.
  97. for (auto& entry : is_uvpaa_callbacks_) {
  98. std::move(entry.second).Run(false);
  99. }
  100. is_uvpaa_callbacks_.clear();
  101. VLOG(1) << "Number of bound receivers on disconnecting: "
  102. << receiver_set_.size();
  103. receiver_set_.Clear();
  104. NotifyWebAuthnStateChange();
  105. }
  106. void RemoteWebAuthnMessageHandler::
  107. IsUserVerifyingPlatformAuthenticatorAvailable(
  108. IsUserVerifyingPlatformAuthenticatorAvailableCallback callback) {
  109. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  110. uint64_t id = AssignNextMessageId();
  111. is_uvpaa_callbacks_[id] = std::move(callback);
  112. protocol::RemoteWebAuthn remote_webauthn;
  113. remote_webauthn.set_id(id);
  114. // This simply creates the is_uvpaa_request.
  115. remote_webauthn.mutable_is_uvpaa_request();
  116. Send(remote_webauthn, base::DoNothing());
  117. }
  118. void RemoteWebAuthnMessageHandler::Create(
  119. const std::string& request_data,
  120. mojo::PendingReceiver<mojom::WebAuthnRequestCanceller> request_canceller,
  121. CreateCallback callback) {
  122. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  123. uint64_t id = AssignNextMessageId();
  124. create_callbacks_[id] = std::move(callback);
  125. AddRequestCanceller(id, std::move(request_canceller));
  126. protocol::RemoteWebAuthn remote_webauthn;
  127. remote_webauthn.set_id(id);
  128. remote_webauthn.mutable_create_request()->set_request_details_json(
  129. request_data);
  130. Send(remote_webauthn, base::DoNothing());
  131. }
  132. void RemoteWebAuthnMessageHandler::Get(
  133. const std::string& request_data,
  134. mojo::PendingReceiver<mojom::WebAuthnRequestCanceller> request_canceller,
  135. GetCallback callback) {
  136. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  137. uint64_t id = AssignNextMessageId();
  138. get_callbacks_[id] = std::move(callback);
  139. AddRequestCanceller(id, std::move(request_canceller));
  140. protocol::RemoteWebAuthn remote_webauthn;
  141. remote_webauthn.set_id(id);
  142. remote_webauthn.mutable_get_request()->set_request_details_json(request_data);
  143. Send(remote_webauthn, base::DoNothing());
  144. }
  145. void RemoteWebAuthnMessageHandler::Cancel(CancelCallback callback) {
  146. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  147. uint64_t id = request_cancellers_.current_context();
  148. if (!base::Contains(create_callbacks_, id) &&
  149. !base::Contains(get_callbacks_, id)) {
  150. LOG(ERROR) << "No ongoing request is associated with message ID " << id;
  151. std::move(callback).Run(false);
  152. RemoveRequestCancellerByMessageId(id);
  153. return;
  154. }
  155. cancel_callbacks_[id] = std::move(callback);
  156. protocol::RemoteWebAuthn remote_webauthn;
  157. remote_webauthn.set_id(id);
  158. // This creates an empty cancel request.
  159. remote_webauthn.mutable_cancel_request();
  160. Send(remote_webauthn, base::DoNothing());
  161. }
  162. void RemoteWebAuthnMessageHandler::AddReceiver(
  163. mojo::PendingReceiver<mojom::WebAuthnProxy> receiver) {
  164. if (!connected()) {
  165. LOG(WARNING)
  166. << "Pending receiver rejected since message handler is not connected.";
  167. return;
  168. }
  169. mojo::ReceiverId id = receiver_set_.Add(this, std::move(receiver));
  170. VLOG(1) << "New receiver added. Receiver ID: " << id;
  171. }
  172. void RemoteWebAuthnMessageHandler::ClearReceivers() {
  173. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  174. receiver_set_.Clear();
  175. request_cancellers_.Clear();
  176. message_id_to_request_canceller_.clear();
  177. is_uvpaa_callbacks_.clear();
  178. create_callbacks_.clear();
  179. get_callbacks_.clear();
  180. cancel_callbacks_.clear();
  181. }
  182. void RemoteWebAuthnMessageHandler::NotifyWebAuthnStateChange() {
  183. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  184. state_change_notifier_->NotifyStateChange();
  185. }
  186. base::WeakPtr<RemoteWebAuthnMessageHandler>
  187. RemoteWebAuthnMessageHandler::GetWeakPtr() {
  188. return weak_factory_.GetWeakPtr();
  189. }
  190. void RemoteWebAuthnMessageHandler::OnReceiverDisconnected() {
  191. VLOG(1) << "Receiver disconnected. Receiver ID: "
  192. << receiver_set_.current_receiver();
  193. }
  194. void RemoteWebAuthnMessageHandler::OnIsUvpaaResponse(
  195. uint64_t id,
  196. const protocol::RemoteWebAuthn_IsUvpaaResponse& response) {
  197. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  198. FindAndRunCallback(is_uvpaa_callbacks_, id, response.is_available());
  199. }
  200. void RemoteWebAuthnMessageHandler::OnCreateResponse(
  201. uint64_t id,
  202. const protocol::RemoteWebAuthn_CreateResponse& response) {
  203. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  204. mojom::WebAuthnCreateResponsePtr mojo_response;
  205. switch (response.result_case()) {
  206. case protocol::RemoteWebAuthn::CreateResponse::ResultCase::kError:
  207. mojo_response = mojom::WebAuthnCreateResponse::NewErrorDetails(
  208. ProtobufErrorToMojoError(response.error()));
  209. break;
  210. case protocol::RemoteWebAuthn::CreateResponse::ResultCase::kResponseJson:
  211. mojo_response = mojom::WebAuthnCreateResponse::NewResponseData(
  212. response.response_json());
  213. break;
  214. case protocol::RemoteWebAuthn::CreateResponse::ResultCase::RESULT_NOT_SET:
  215. // Do nothing and send a nullptr to the mojo client. This means the remote
  216. // create() call has yielded `null`, which is still a valid response
  217. // according to the spec.
  218. break;
  219. default:
  220. NOTREACHED() << "Unknown create result case: " << response.result_case();
  221. }
  222. RemoveRequestCancellerByMessageId(id);
  223. FindAndRunCallback(create_callbacks_, id, std::move(mojo_response));
  224. }
  225. void RemoteWebAuthnMessageHandler::OnGetResponse(
  226. uint64_t id,
  227. const protocol::RemoteWebAuthn_GetResponse& response) {
  228. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  229. mojom::WebAuthnGetResponsePtr mojo_response;
  230. switch (response.result_case()) {
  231. case protocol::RemoteWebAuthn::GetResponse::ResultCase::kError:
  232. mojo_response = mojom::WebAuthnGetResponse::NewErrorDetails(
  233. ProtobufErrorToMojoError(response.error()));
  234. break;
  235. case protocol::RemoteWebAuthn::GetResponse::ResultCase::kResponseJson:
  236. mojo_response =
  237. mojom::WebAuthnGetResponse::NewResponseData(response.response_json());
  238. break;
  239. case protocol::RemoteWebAuthn::GetResponse::ResultCase::RESULT_NOT_SET:
  240. // Do nothing and send a nullptr to the mojo client. This means the remote
  241. // get() call has yielded `null`, which is still a valid response
  242. // according to the spec.
  243. break;
  244. default:
  245. NOTREACHED() << "Unknown get result case: " << response.result_case();
  246. }
  247. RemoveRequestCancellerByMessageId(id);
  248. FindAndRunCallback(get_callbacks_, id, std::move(mojo_response));
  249. }
  250. void RemoteWebAuthnMessageHandler::OnCancelResponse(
  251. uint64_t id,
  252. const protocol::RemoteWebAuthn_CancelResponse& response) {
  253. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  254. if (!response.was_canceled()) {
  255. LOG(WARNING) << "Client failed to cancel request with ID " << id;
  256. FindAndRunCallback(cancel_callbacks_, id, /* was_canceled= */ false);
  257. // Don't remove request canceller here since cancelation might succeed after
  258. // retrying.
  259. return;
  260. }
  261. bool cancelling_create_request = base::Contains(create_callbacks_, id);
  262. bool cancelling_get_request = base::Contains(get_callbacks_, id);
  263. if (cancelling_create_request || cancelling_get_request) {
  264. FindAndRunCallback(cancel_callbacks_, id, /* was_canceled= */ true);
  265. if (cancelling_create_request) {
  266. FindAndRunCallback(create_callbacks_, id,
  267. mojom::WebAuthnCreateResponse::NewErrorDetails(
  268. CreateMojoAbortError()));
  269. }
  270. if (cancelling_get_request) {
  271. // The ID should belong to only one callback list.
  272. DCHECK(!cancelling_create_request);
  273. FindAndRunCallback(
  274. get_callbacks_, id,
  275. mojom::WebAuthnGetResponse::NewErrorDetails(CreateMojoAbortError()));
  276. }
  277. RemoveRequestCancellerByMessageId(id);
  278. return;
  279. }
  280. LOG(WARNING) << "Can't find cancelable request associated with ID " << id;
  281. FindAndRunCallback(cancel_callbacks_, id, /* was_canceled= */ false);
  282. RemoveRequestCancellerByMessageId(id);
  283. }
  284. uint64_t RemoteWebAuthnMessageHandler::AssignNextMessageId() {
  285. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  286. return current_message_id_++;
  287. }
  288. void RemoteWebAuthnMessageHandler::AddRequestCanceller(
  289. uint64_t message_id,
  290. mojo::PendingReceiver<mojom::WebAuthnRequestCanceller> request_canceller) {
  291. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  292. message_id_to_request_canceller_[message_id] = request_cancellers_.Add(
  293. this, std::move(request_canceller), /* context= */ message_id);
  294. }
  295. void RemoteWebAuthnMessageHandler::RemoveRequestCancellerByMessageId(
  296. uint64_t message_id) {
  297. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  298. auto it = message_id_to_request_canceller_.find(message_id);
  299. if (it != message_id_to_request_canceller_.end()) {
  300. request_cancellers_.Remove(it->second);
  301. message_id_to_request_canceller_.erase(it);
  302. } else {
  303. LOG(WARNING) << "Cannot find receiver for message ID " << message_id;
  304. }
  305. }
  306. void RemoteWebAuthnMessageHandler::OnRequestCancellerDisconnected() {
  307. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  308. message_id_to_request_canceller_.erase(request_cancellers_.current_context());
  309. }
  310. } // namespace remoting