webauthn_browser_bridge.cc 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Copyright 2022 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 "components/webauthn/android/webauthn_browser_bridge.h"
  5. #include <jni.h>
  6. #include "base/android/callback_android.h"
  7. #include "base/android/jni_array.h"
  8. #include "base/android/jni_string.h"
  9. #include "base/android/scoped_java_ref.h"
  10. #include "components/webauthn/android/jni_headers/WebAuthnBrowserBridge_jni.h"
  11. #include "components/webauthn/android/webauthn_client_android.h"
  12. #include "content/public/browser/render_frame_host.h"
  13. #include "device/fido/discoverable_credential_metadata.h"
  14. #include "device/fido/public_key_credential_user_entity.h"
  15. using base::android::ScopedJavaLocalRef;
  16. device::DiscoverableCredentialMetadata ConvertJavaCredentialDetailsToMetadata(
  17. JNIEnv* env,
  18. ScopedJavaLocalRef<jobject> j_credential) {
  19. device::DiscoverableCredentialMetadata credential;
  20. base::android::JavaByteArrayToByteVector(
  21. env,
  22. Java_WebAuthnBrowserBridge_getWebAuthnCredentialDetailsCredentialId(
  23. env, j_credential),
  24. &credential.cred_id);
  25. base::android::JavaByteArrayToByteVector(
  26. env,
  27. Java_WebAuthnBrowserBridge_getWebAuthnCredentialDetailsUserId(
  28. env, j_credential),
  29. &credential.user.id);
  30. credential.user.name = ConvertJavaStringToUTF8(
  31. env, Java_WebAuthnBrowserBridge_getWebAuthnCredentialDetailsUserName(
  32. env, j_credential));
  33. credential.user.display_name = ConvertJavaStringToUTF8(
  34. env,
  35. Java_WebAuthnBrowserBridge_getWebAuthnCredentialDetailsUserDisplayName(
  36. env, j_credential));
  37. return credential;
  38. }
  39. void ConvertJavaCredentialArrayToMetadataVector(
  40. JNIEnv* env,
  41. const base::android::JavaRef<jobjectArray>& array,
  42. std::vector<device::DiscoverableCredentialMetadata>* out) {
  43. jsize jlength = env->GetArrayLength(array.obj());
  44. // GetArrayLength() returns -1 if |array| is not a valid Java array.
  45. DCHECK_GE(jlength, 0) << "Invalid array length: " << jlength;
  46. size_t length = static_cast<size_t>(std::max(0, jlength));
  47. for (size_t i = 0; i < length; ++i) {
  48. ScopedJavaLocalRef<jobject> j_credential(
  49. env, static_cast<jobject>(env->GetObjectArrayElement(array.obj(), i)));
  50. out->emplace_back(
  51. ConvertJavaCredentialDetailsToMetadata(env, j_credential));
  52. }
  53. }
  54. void OnWebAuthnCredentialSelected(
  55. const base::android::JavaRef<jobject>& jcallback,
  56. const std::vector<uint8_t>& credential_id) {
  57. base::android::RunObjectCallbackAndroid(
  58. jcallback, base::android::ToJavaByteArray(
  59. base::android::AttachCurrentThread(), credential_id.data(),
  60. credential_id.size()));
  61. }
  62. static jlong JNI_WebAuthnBrowserBridge_CreateNativeWebAuthnBrowserBridge(
  63. JNIEnv* env,
  64. const base::android::JavaParamRef<jobject>& jbridge) {
  65. return reinterpret_cast<jlong>(new WebAuthnBrowserBridge(env, jbridge));
  66. }
  67. WebAuthnBrowserBridge::WebAuthnBrowserBridge(
  68. JNIEnv* env,
  69. const base::android::JavaParamRef<jobject>& jbridge)
  70. : owner_(env, jbridge) {}
  71. WebAuthnBrowserBridge::~WebAuthnBrowserBridge() = default;
  72. void WebAuthnBrowserBridge::OnCredentialsDetailsListReceived(
  73. JNIEnv* env,
  74. const base::android::JavaParamRef<jobject>&,
  75. const base::android::JavaParamRef<jobjectArray>& credentials,
  76. const base::android::JavaParamRef<jobject>& jframe_host,
  77. const base::android::JavaParamRef<jobject>& jcallback) const {
  78. auto* client = components::WebAuthnClientAndroid::GetClient();
  79. auto* render_frame_host =
  80. content::RenderFrameHost::FromJavaRenderFrameHost(jframe_host);
  81. // A null client indicates the embedder does not support Conditional UI.
  82. if (!client) {
  83. std::vector<uint8_t> credential_id = {};
  84. base::android::RunObjectCallbackAndroid(
  85. jcallback, base::android::ToJavaByteArray(
  86. base::android::AttachCurrentThread(),
  87. credential_id.data(), credential_id.size()));
  88. return;
  89. }
  90. DCHECK(render_frame_host);
  91. std::vector<device::DiscoverableCredentialMetadata> credentials_metadata;
  92. ConvertJavaCredentialArrayToMetadataVector(env, credentials,
  93. &credentials_metadata);
  94. client->OnWebAuthnRequestPending(
  95. render_frame_host, credentials_metadata,
  96. base::BindOnce(
  97. &OnWebAuthnCredentialSelected,
  98. base::android::ScopedJavaGlobalRef<jobject>(env, jcallback)));
  99. }