| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/webauthn/android/internal_authenticator_android.h" |
| |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/android/jni_android.h" |
| #include "base/android/jni_array.h" |
| #include "base/android/jni_string.h" |
| #include "base/timer/timer.h" |
| #include "components/webauthn/android/jni_headers/InternalAuthenticator_jni.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/web_contents.h" |
| #include "mojo/public/cpp/base/time_mojom_traits.h" |
| #include "mojo/public/mojom/base/time.mojom.h" |
| #include "third_party/blink/public/mojom/authenticator_mojom_traits.h" |
| #include "third_party/blink/public/mojom/webauthn/authenticator.mojom-blink.h" |
| #include "url/origin.h" |
| |
| using base::android::AttachCurrentThread; |
| using base::android::ConvertUTF8ToJavaString; |
| using base::android::JavaRef; |
| using base::android::ScopedJavaLocalRef; |
| using base::android::ToJavaArrayOfByteArray; |
| |
| InternalAuthenticatorAndroid::InternalAuthenticatorAndroid( |
| content::RenderFrameHost* render_frame_host) |
| : render_frame_host_id_(render_frame_host->GetGlobalId()) { |
| JNIEnv* env = AttachCurrentThread(); |
| java_internal_authenticator_ref_ = Java_InternalAuthenticator_create( |
| env, reinterpret_cast<intptr_t>(this), |
| render_frame_host->GetJavaRenderFrameHost()); |
| } |
| |
| InternalAuthenticatorAndroid::~InternalAuthenticatorAndroid() { |
| JNIEnv* env = AttachCurrentThread(); |
| DCHECK(!java_internal_authenticator_ref_.is_null()); |
| Java_InternalAuthenticator_clearNativePtr(env, |
| java_internal_authenticator_ref_); |
| } |
| |
| void InternalAuthenticatorAndroid::SetEffectiveOrigin( |
| const url::Origin& origin) { |
| JNIEnv* env = AttachCurrentThread(); |
| JavaRef<jobject>& obj = GetJavaObject(); |
| DCHECK(!obj.is_null()); |
| |
| Java_InternalAuthenticator_setEffectiveOrigin(env, obj, |
| origin.CreateJavaObject()); |
| } |
| |
| void InternalAuthenticatorAndroid::SetPaymentOptions( |
| blink::mojom::PaymentOptionsPtr payment) { |
| JNIEnv* env = AttachCurrentThread(); |
| JavaRef<jobject>& obj = GetJavaObject(); |
| DCHECK(!obj.is_null()); |
| |
| std::vector<uint8_t> byte_vector = |
| blink::mojom::PaymentOptions::Serialize(&payment); |
| ScopedJavaLocalRef<jobject> byte_buffer = ScopedJavaLocalRef<jobject>( |
| env, env->NewDirectByteBuffer(byte_vector.data(), byte_vector.size())); |
| base::android::CheckException(env); |
| |
| Java_InternalAuthenticator_setPaymentOptions(env, obj, byte_buffer); |
| } |
| |
| void InternalAuthenticatorAndroid::MakeCredential( |
| blink::mojom::PublicKeyCredentialCreationOptionsPtr options, |
| blink::mojom::Authenticator::MakeCredentialCallback callback) { |
| JNIEnv* env = AttachCurrentThread(); |
| JavaRef<jobject>& obj = GetJavaObject(); |
| DCHECK(!obj.is_null()); |
| |
| make_credential_response_callback_ = std::move(callback); |
| |
| std::vector<uint8_t> byte_vector = |
| blink::mojom::PublicKeyCredentialCreationOptions::Serialize(&options); |
| ScopedJavaLocalRef<jobject> byte_buffer = ScopedJavaLocalRef<jobject>( |
| env, env->NewDirectByteBuffer(byte_vector.data(), byte_vector.size())); |
| base::android::CheckException(env); |
| |
| Java_InternalAuthenticator_makeCredential(env, obj, byte_buffer); |
| } |
| |
| void InternalAuthenticatorAndroid::GetAssertion( |
| blink::mojom::PublicKeyCredentialRequestOptionsPtr options, |
| blink::mojom::Authenticator::GetAssertionCallback callback) { |
| JNIEnv* env = AttachCurrentThread(); |
| JavaRef<jobject>& obj = GetJavaObject(); |
| DCHECK(!obj.is_null()); |
| |
| get_assertion_response_callback_ = std::move(callback); |
| |
| std::vector<uint8_t> byte_vector = |
| blink::mojom::PublicKeyCredentialRequestOptions::Serialize(&options); |
| ScopedJavaLocalRef<jobject> byte_buffer = ScopedJavaLocalRef<jobject>( |
| env, env->NewDirectByteBuffer(byte_vector.data(), byte_vector.size())); |
| base::android::CheckException(env); |
| |
| Java_InternalAuthenticator_getAssertion(env, obj, byte_buffer); |
| } |
| |
| void InternalAuthenticatorAndroid:: |
| IsUserVerifyingPlatformAuthenticatorAvailable( |
| blink::mojom::Authenticator:: |
| IsUserVerifyingPlatformAuthenticatorAvailableCallback callback) { |
| JNIEnv* env = AttachCurrentThread(); |
| JavaRef<jobject>& obj = GetJavaObject(); |
| DCHECK(!obj.is_null()); |
| |
| is_uvpaa_callback_ = std::move(callback); |
| Java_InternalAuthenticator_isUserVerifyingPlatformAuthenticatorAvailable(env, |
| obj); |
| } |
| |
| bool InternalAuthenticatorAndroid::IsGetMatchingCredentialIdsSupported() { |
| JNIEnv* env = AttachCurrentThread(); |
| JavaRef<jobject>& obj = GetJavaObject(); |
| DCHECK(!obj.is_null()); |
| |
| return Java_InternalAuthenticator_isGetMatchingCredentialIdsSupported(env, |
| obj); |
| } |
| |
| void InternalAuthenticatorAndroid::GetMatchingCredentialIds( |
| const std::string& relying_party_id, |
| const std::vector<std::vector<uint8_t>>& credential_ids, |
| bool require_third_party_payment_bit, |
| webauthn::GetMatchingCredentialIdsCallback callback) { |
| JNIEnv* env = AttachCurrentThread(); |
| JavaRef<jobject>& obj = GetJavaObject(); |
| DCHECK(!obj.is_null()); |
| |
| get_matching_credential_ids_callback_ = std::move(callback); |
| Java_InternalAuthenticator_getMatchingCredentialIds( |
| env, obj, ConvertUTF8ToJavaString(env, relying_party_id), |
| ToJavaArrayOfByteArray(env, std::move(credential_ids)), |
| require_third_party_payment_bit); |
| } |
| |
| void InternalAuthenticatorAndroid::Cancel() { |
| JNIEnv* env = AttachCurrentThread(); |
| JavaRef<jobject>& obj = GetJavaObject(); |
| DCHECK(!obj.is_null()); |
| |
| Java_InternalAuthenticator_cancel(env, obj); |
| } |
| |
| content::RenderFrameHost* InternalAuthenticatorAndroid::GetRenderFrameHost() { |
| return content::RenderFrameHost::FromID(render_frame_host_id_); |
| } |
| |
| void InternalAuthenticatorAndroid::InvokeMakeCredentialResponse( |
| JNIEnv* env, |
| jint status, |
| const base::android::JavaParamRef<jobject>& byte_buffer) { |
| blink::mojom::MakeCredentialAuthenticatorResponsePtr response; |
| |
| // |byte_buffer| may be null if authentication failed. |
| if (byte_buffer) { |
| jbyte* buf_in = |
| static_cast<jbyte*>(env->GetDirectBufferAddress(byte_buffer.obj())); |
| jlong buf_size = env->GetDirectBufferCapacity(byte_buffer.obj()); |
| blink::mojom::MakeCredentialAuthenticatorResponse::Deserialize( |
| buf_in, buf_size, &response); |
| } |
| |
| DCHECK_NE( |
| status, |
| static_cast<int>( |
| blink::mojom::AuthenticatorStatus::ERROR_WITH_DOM_EXCEPTION_DETAILS)); |
| std::move(make_credential_response_callback_) |
| .Run(static_cast<blink::mojom::AuthenticatorStatus>(status), |
| std::move(response), /*dom_exception_details=*/nullptr); |
| } |
| |
| void InternalAuthenticatorAndroid::InvokeGetAssertionResponse( |
| JNIEnv* env, |
| jint status, |
| const base::android::JavaParamRef<jobject>& byte_buffer) { |
| blink::mojom::GetAssertionAuthenticatorResponsePtr response; |
| |
| // |byte_buffer| may be null if authentication failed. |
| if (byte_buffer) { |
| jbyte* buf_in = |
| static_cast<jbyte*>(env->GetDirectBufferAddress(byte_buffer.obj())); |
| jlong buf_size = env->GetDirectBufferCapacity(byte_buffer.obj()); |
| blink::mojom::GetAssertionAuthenticatorResponse::Deserialize( |
| buf_in, buf_size, &response); |
| } |
| |
| DCHECK_NE( |
| status, |
| static_cast<int>( |
| blink::mojom::AuthenticatorStatus::ERROR_WITH_DOM_EXCEPTION_DETAILS)); |
| std::move(get_assertion_response_callback_) |
| .Run(static_cast<blink::mojom::AuthenticatorStatus>(status), |
| std::move(response), /*dom_exception_details=*/nullptr); |
| } |
| |
| void InternalAuthenticatorAndroid:: |
| InvokeIsUserVerifyingPlatformAuthenticatorAvailableResponse( |
| JNIEnv* env, |
| jboolean is_uvpaa) { |
| std::move(is_uvpaa_callback_).Run(static_cast<bool>(is_uvpaa)); |
| } |
| |
| void InternalAuthenticatorAndroid::InvokeGetMatchingCredentialIdsResponse( |
| JNIEnv* env, |
| const base::android::JavaParamRef<jobjectArray>& credential_ids_array) { |
| std::vector<std::vector<uint8_t>> credential_ids; |
| JavaArrayOfByteArrayToBytesVector(env, credential_ids_array, &credential_ids); |
| std::move(get_matching_credential_ids_callback_) |
| .Run(std::move(credential_ids)); |
| } |
| |
| JavaRef<jobject>& InternalAuthenticatorAndroid::GetJavaObject() { |
| if (java_internal_authenticator_ref_.is_null()) { |
| JNIEnv* env = AttachCurrentThread(); |
| java_internal_authenticator_ref_ = Java_InternalAuthenticator_create( |
| env, reinterpret_cast<intptr_t>(this), |
| GetRenderFrameHost()->GetJavaRenderFrameHost()); |
| } |
| return java_internal_authenticator_ref_; |
| } |